2

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;
}
asked Jan 9, 2017 at 13:17
5
  • Unrelated to your problem, but why create a thread if the next thing you do is just to wait for it? I assume you do something else between the thread creation and the join call? Maybe the problem is that part (that you don't show us)? Commented Jan 9, 2017 at 13:21
  • I'd be interested to see how you fix this. I know enough C++ to spot the problem (per my answer), but not to fix it. I wonder if just writing std::thread job(std::ref(dm)) would be sufficient. Commented Jan 9, 2017 at 13:45
  • @Alnitak I've run quick test and std::ref() solves problem. But I guess that will not be sufficient in "large scale", or when I will try to get rid off this join() call. Commented Jan 9, 2017 at 13:48
  • Right, because you have to ensure that dm doesn't get destroyed when it goes out of scope when your server_run function finishes while the thread is still trying to use that object. Hmm... Commented Jan 9, 2017 at 13:51
  • 1
    It seems to me like you need to implement a move constructor, such that when you call std::thread job(dm) only the new instance of the object maintains the file descriptor (and gains responsibility for closing it) and the original learns that it no longer has to (perhaps by setting socket_fd to a negative value to signal that) Commented Jan 9, 2017 at 13:55

1 Answer 1

4

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.

answered Jan 9, 2017 at 13:28
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.