Search code examples
c++linuxmultithreadingsocketsstdthread

Linux Socket file descriptor with threads


consider following situation: One thread (lets call it A) initialises, sets socket state with listen() and then wait with accept(). Connection arrives to A socket, accept() returns valid fd. New thread (B) is created (using std::thread), and acquired fd is passed to a callable object witch runs in thread B. Reading (using read()) for fd fails and errno is set to 9 EBADFD. Thread A calls join() on B. When B is not spawned and fd is used (still via same callable object) read completes without failure. Why? Below is some code to illustrate this situation.

BaseFun::BaseFun(char* bufferAdr, int socket):
    socket_fd(socket)
    buffer(bufferAdr)
{}

BaseFun::~BaseFun()
{
    close(socket_fd);
}

char* BaseFun::buffer_read()
{
    if(read(socket_fd, buffer, BUFF_SIZE-1) < 0) {
        std::cout<<"ERROR while READ\n"<<"ERRNO: "<<errno<<"\n"<<"FD: "<<socket_fd<<"\n";
    }
    return buffer;
}

DisplayMsgFun::DisplayMsgFun(char* buffer, int socket) :
    BaseFun(buffer, socket)
{}

void DisplayMsgFunFun::operator()()
{
    std::cout<<"Message:\n\t"<<buffer_read()<<"\nEND\n";
}

Snippet where above is called:

void Server::server_run()
{
    sockaddr_in client_addr;
    socklen_t c_len = sizeof(client_addr);

    client_fd = accept(sock_fd, (sockaddr*)&client_addr, &c_len);
    DisplayMsgFun dm(server_buffers->front().data(), client_fd);
    std::thread job(dm);
    job.join();
}

And main()

int main()
{
    Server srv(PORT);
    if (srv.server_create()) {
        std::cout << "Server bind!\n";
        srv.server_run();
    }
    else {
        std::cout << "Bind fail! ERRNO: "<<errno<<"\n";
        return -1;
    }
    return 0;
}

Solution

  • You appear to be passing a copy of the DisplayMsgFun object to the std::thread constructor, which means that the original copy gets destroyed, automatically calling ::close per your destructor.