0

I am writing a server application that spawns a new thread for each client connection. I want to make sure all client threads have exited before the main thread exits. This is because according to answers to the question 'What happens to a detached thread when main() exits?' it is undefined behavior if I return from main() before all detached threads have terminated.

Simply storing all std::thread instances in a container and calling std::thread::join() on all of them before I return from main() is not an option because I might collect a huge amount of thread handles over time. However, joining threads every now and then is also not an option because std::thread::join() might block for too long and make my server unable to accept new connections.

Therefore I need some mechanism to either reliably wait for detached threads before I return from main() or find a way to implement a non-blocking version of std::thread::join. There have been plenty of similar questions asked before:

Answers there propose to use std::async together with std::future, std::promise, or std::condition_variable. But according to the already mentioned question all these mechanisms do not guarantee that the worker thread has really finished executing.

Are std::promise::set_value_at_thread_exit(), std::notify_all_at_thread_exit and std::packaged_task::make_ready_at_thread_exit really the only solutions?

sigy
  • 2,408
  • 1
  • 24
  • 55
  • `std::async` is not mentioned in the linked question. Can you clarify why you think the question applies to `std::async`? – Yakk - Adam Nevraumont Jul 12 '17 at 12:47
  • Are you heavily using thread local storage? If not, the time between the "last line" of the thread and the thread being gone isn't going to be insane. And is there a reason why the connection-accepting thread has to be the one that cleans up old threads? – Yakk - Adam Nevraumont Jul 12 '17 at 12:50
  • Why would "join with timeout" not guarantee that the thread has really finished executing? – freakish Jul 12 '17 at 12:51
  • By the way, I'm not sure what you are trying to achieve. You want to exit the main thread (so you need to wait for other threads) yet you are saying `might block for too long and make my server unable to accept new connections`. You can't simultanously exit and accept new connections. This doesn't make sense. Once you decide to exit you have to stop accepting, close the server socket and fire cleaning code (e.g. joins), right? – freakish Jul 12 '17 at 12:56
  • @Yakk My understanding is that it is not guaranteed that once the result in the future is available the thread has really finished executing. Is this wrong? The connection-accepting thread does not have to be the one performing cleanup but moving it to another thread would suffer under the same problem, wouldn't it? – sigy Jul 12 '17 at 13:03
  • @freakish There is no "join with timeout" that I am aware of. What I am trying to archive is freeing thread handles from time to time and terminating gracefully. Freeing handles is what might block the connection-accepting thread if I simply use `std::thread::join()`. – sigy Jul 12 '17 at 13:07
  • @sigy I'm asking about the [Timeout for thread.join()](https://stackoverflow.com/questions/9948420/timeout-for-thread-join) article you've mentioned. Why do you say `all these mechanisms do not guarantee that the worker thread has really finished executing.`? Once a thread reaches `cv.notify_all();` it will exit. – freakish Jul 12 '17 at 13:09
  • @sigy And again, why would you accept new connections when you want to exit??? This doesn't make sense. With that you may **never** exit. If someone writes a loop creating new connections, you will never exit. – freakish Jul 12 '17 at 13:10
  • @freakish I am not accepting new connections when I want to exit. The proposed solution In the question you mention is to use `std::condition_variable`. But there will be code executed in the worker thread after the call to `notify_all()`. – sigy Jul 12 '17 at 13:14
  • @sigy I really don't get it. If you don't accept connections then simply `join()` all threads. What is the problem? Even if it takes some time so what? What is the main thread supposed to do in the meantime? :) Also yes, you have to modify the worker thread. And why is that a problem? You can wrap your worker thread with a proper function as suggested in the article. – freakish Jul 12 '17 at 13:17
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/149009/discussion-between-sigy-and-freakish). – sigy Jul 12 '17 at 13:18
  • @sigy The cleanup thread blocking doesn't prevent you from establishing new connections, unlike the main thread. Again, I understand how you *believe* `std::async` doesn't work in this case, but you then said your belief was based off a SO Q&A, and I didn't *see* any evidence there to back your claim; is there an actual SO Q&A that backs your claim? If not, why do you think that? Before I spend effort refuting what I believe to be an error of yours (but I am not certain), if you already have evidence that could save my time. – Yakk - Adam Nevraumont Jul 12 '17 at 13:21
  • @Yakk It probably is an error of mine. I just _assumed_ it to be like this because it is not mentioned in the linked answer. However, I now see that this probably is because the OP over there was only talking about already detached threads. – sigy Jul 12 '17 at 13:36

0 Answers0