
On Oct 11, 2006, at 5:19 PM, Peter Dimov wrote:
1. I have an application that creates lots of relatively short-lived threads. When a thread is created I store the handle in an array, and at regular intervals, I remove completed threads from the array by checking the thread state via ::GetExitCodeThread. The application runs 24/7 so I don't want an array containing thousands of "dead" handles.
I thought I'd replace this code with a boost::thread_group, but I cannot see any way to remove completed threads from the internal list. This means the std::list used by boost::thread_group would keep on increasing in size until the application exits, which I want to avoid. If I decide to roll my own thread group code, how can I check if a boost::thread is still active or not?
You can't.
Interesting timing; I submitted a proposal for a threading API to the C++ committee:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2090.html
that lets you do that. You can keep a vector< thread::handle > and periodically sweep it using thread::try_join as a predicate. I've been having troubles convincing some committee members of its utility, though.
For the record, I'm the committee member Peter speaks of here. And yes, Peter has been having trouble convincing me that a copyable std::thread is in our best interest for C++0X. However I'm fully convinced of the utility of std::vector<std::thread>. In C++0X this should require only movability, not copyability. Containers of threads should be extremely useful, and I'm aware that the lack of this functionality for boost::thread is frustrating. C++0X should elegantly lift this restriction, allowing vector<thread>. I know this doesn't help you today. But my job is to plan for C++0X, not boost, sorry. The other functionality you request, thread::try_join(), is not supported by myself. However I am supporting higher level standard- supplied objects that do support try_join() (with a different spelling, but I'm not concerned about the spelling for now). For example: std::vector<std::future<void>> v; ... v.push_back(std::launch_in_thread(some_functional)); ... if (v.back().ready()) // try_join // join with it else // do something else The cost of std::future<void> is approximately the same cost as Peter's copyable thread with try_join functionality, but significantly more expensive than today's boost::thread (or my proposed std::thread, approximately equivalent to boost::thread). When it is obtained from std::launch_in_thread, there is a one to one mapping of it to an OS thread and it has "try_join" functionality. Reference: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2094.html Therein, you'll also find a std::thread_pool which may be even more applicable to your design constraints: std::vector<std::future<void>> v; std::thread_pool launch_in_pool; ... v.push_back(launch_in_pool(some_functional)); ... if (v.back().ready()) // try_join // join with it else // do something else In a nutshell, I think the availability of move semantics in C++0X strongly impacts the multithreading API that should be designed. I also believe a layered approach is pragmatics. Clients can pay for only what functionality they need (boost::thread while spartan, is quite useful, and will become even more so when movable). I'm quite interested to hear about use cases such as yours to make sure we are covering these bases, with a minimum of cost, and a maximum of efficiency/performance across as many platforms as we can manage. -Howard