boost::thread queries
I have just started to investigate the boost::thread library and have a couple of questions (Win32/VS2005): 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? 2. I am getting a memory leak when my application exits, which has already been mentioned here. Does anyone have a fix for this which I can apply to the 1.33.1 source (then rebuilding the thread lib by hand)? It would be much appreciated. I am also unsure if this leak will be fixed for 1.34 - does anyone know for certain? Thanks in advance.
Rob Caldecott wrote:
I have just started to investigate the boost::thread library and have a couple of questions (Win32/VS2005):
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. That said, why do you even have to keep the boost::thread objects? There aren't many useful things that you could do with a boost::thread; if you run 24/7 you should be able to just spawn the threads "detached": boost::thread( f ); without keeping them in a thread group.
2. I am getting a memory leak when my application exits, which has already been mentioned here. Does anyone have a fix for this which I can apply to the 1.33.1 source (then rebuilding the thread lib by hand)? It would be much appreciated. I am also unsure if this leak will be fixed for 1.34 - does anyone know for certain?
You can replace your version of tss_hooks.cpp with this one: http://boost.cvs.sourceforge.net/*checkout*/boost/boost/libs/thread/src/tss_... and rebuild. 1.34 does contain a fix for that too, albeit a different one.
That said, why do you even have to keep the boost::thread objects? There aren't many useful things that you could do with a boost::thread; if you run 24/7 you should be able to just spawn the threads "detached":
The threads are doing socket stuff, and I want to terminate them gracefully when the application exits (currently they use a shared event that I signal when its time to terminate). I don't like the idea of my application closing while socket threads are still active - I like things to be as clean as possible.
You can replace your version of tss_hooks.cpp with this one:
Thankyou! Just what I was after. FWIW, I think your try_join proposal is an excellent idea.
Peter Dimov
That said, why do you even have to keep the boost::thread objects? There aren't many useful things that you could do with a boost::thread; if you run 24/7 you should be able to just spawn the threads "detached":
boost::thread( f );
without keeping them in a thread group.
Hi,
On Windows the ~thread() doesnot detach the thread. Hence, the below listed
code will throw boost::thread_resource_error().
int num_threads = 0;
while(true)
{
try
{
boost::thread thr(f);
++num_threads;
}
catch (const std::exception & e)
{
std::cout<<"Exception..."<
Prashant Thakre wrote:
On Windows the ~thread() doesnot detach the thread. Hence, the below listed code will throw boost::thread_resource_error().
... <example snipped> ... What do you expect? You cant simply create threads beyond the system limits, which is roughly 2000 on my box. I tried your code with a really short lived thread: by using function void f() {}. This runs "forever". When running in a debugger, then setting a breakpoint, you will see no threads beyond the main running. When changing f to void f() { Sleep(100000); } however the resource exception will be thrown when the system runs out of resources, which happend around 2000 in my case. BTW.: There might be a misconception about the usage of threads. One normally wouldn't like to pay the cost of starting up a thread for short lived tasks. Instead you would create a queue of jobs that have to be done, and a pool (of fixed size) of threads, which pick a job from the queue. When done they pick the next one, without shuting down the thread in meantime. When the queue is empty, the thread will not stop, but wait on a condition variable signalling that more work is available. I agree that it would be nice if such a jobs queue would be available in boost. But this doesn't strictly belong to boost::threads. This is kind of an abstraction that should be built on top of boost threads. Roland
Roland Schwarz wrote:
I agree that it would be nice if such a jobs queue would be available in boost. But this doesn't strictly belong to boost::threads.
see for http://threadpool.sourceforge.net/ for a nice implementation.
This is kind of an abstraction that should be built on top of boost threads.
yeah! i'd like to see this layer provide more syncronisation related functionality like: - multi threaded containers - futures - locking_ptr - ... what else? cheers sascha
Sascha Seewald wrote:
yeah! i'd like to see this layer provide more syncronisation related functionality like:
- multi threaded containers
like a generic work item queue that buffers between threads, and should allow for fixed size (blocks when full), growable (but bounded) and 'unlimited' size policies. This would allow for the pipeline model.
- futures - locking_ptr
Isn't this what shared_ptr already does... I'd like to see a shared ptr without locking :-) I'd maybe like something layered upon the thread group concept that handles event notifications for the group of threads tied in with the work queue idea. This should work in a generic way so that you would not need to know if it is a single thread or a collection of them available to do the work (Boss-Worker Model) It may be you wish to share the thread groups by considering the type of work done, e.g. separating I/O threads from CPU bound threads by putting them in different pools. Under the pipeline model you could then have separate queues for each stage which signal the appropriate container of the type of thread that there is work to do. This is an off the top of my head formulation which is never a good idea in parallel programming.... so may need refinement :-) Kevin -- | Kevin Wheatley, Cinesite (Europe) Ltd | Nobody thinks this | | Senior Technology | My employer for certain | | And Network Systems Architect | Not even myself |
Kevin Wheatley wrote:
- multi threaded containers
like a generic work item queue that buffers between threads, and should allow for fixed size (blocks when full), growable (but bounded) and 'unlimited' size policies. This would allow for the pipeline model.
yes. in my current project i'm using a queue like this:
template<typename T>
class queue
- locking_ptr
Isn't this what shared_ptr already does... I'd like to see a shared ptr without locking :-)
I was thinking of a pointer that locks on dereference (maybe the name wasn't a good choice). It can be used to synchronize access to objects. foo f; synchronize_ptr<foo> p(&f, monitor); p->do_something(); // sync call to method Of course this isn't very efficient most of the time: p->do1(); p->do2(); p->do3(); This would lock/unlock three times although a single lock/unlock around the calls would have been sufficient. In this case it would be nice to have a lock-mechanism similar to boost::weak_ptr. This way we avoid multiple locks/unlocks: synchronize_ptr<T> p(&f); // sync access to f { lock_ptr<T> l = p.lock(); // blocks // we have exclusive access now l->do1(); l->do2(); l->do3(); } // l goes out of scope -> release lock p itself is not dereferencable (as boost::weak_ptr is not). Does this make any sense?
I'd maybe like something layered upon the thread group concept that handles event notifications for the group of threads tied in with the work queue idea. This should work in a generic way so that you would not need to know if it is a single thread or a collection of them available to do the work (Boss-Worker Model)
It may be you wish to share the thread groups by considering the type of work done, e.g. separating I/O threads from CPU bound threads by putting them in different pools. Under the pipeline model you could then have separate queues for each stage which signal the appropriate container of the type of thread that there is work to do.
This is an off the top of my head formulation which is never a good idea in parallel programming.... so may need refinement :-)
Interesting. Kind of dispatcher delegating queued work items to different worker pools. This should be easy to implement once there is a solid thread_pool implementation available. Sascha
like a generic work item queue that buffers between threads, and should allow for fixed size (blocks when full), growable (but bounded) and 'unlimited' size policies. This would allow for the pipeline model.
yes. in my current project i'm using a queue like this:
template<typename T> class queue
{...} This has static bounds. Using a policy here would allow to change the queues capacity at runtime.
I guess you are not using the STL queue because of the lack of thread safety. I curious if you use a selfmade queue class or a library that is downloadable. At my work we have our own "threadsafe" queue but I'm not so convinced of the robustness of the code. Also, I'm not so conviced what the expected behaviour should be. For example, should a read operation always block until there is an item in the queue? Thanks, Christian
Roland Schwarz
What do you expect? You cant simply create threads beyond the system limits, which is roughly 2000 on my box. I tried your code with a really short lived thread: by using function void f() {}. This runs "forever". When running in a debugger, then setting a breakpoint, you will see no threads beyond the main running.
On Solaris 10, this example works just fine. I am just trying to say that behaviour on Windows is different from what one would observe on systems with pthreads, since storage for the *thread* can be reclaimed when that thread terminates(pthread_detach). I guess one has to necessarily call thread.join() on Windows.
BTW.: There might be a misconception about the usage of threads. One normally wouldn't like to pay the cost of starting up a thread for short lived tasks.
Of course, thread_pool should be used since thread creation is not all that cheap.
I agree that it would be nice if such a jobs queue would be available in boost. But this doesn't strictly belong to boost::threads. This is kind of an abstraction that should be built on top of boost threads.
Roland
-- regards, Prashant
Prashant Thakre wrote:
Roland Schwarz
writes: What do you expect? You cant simply create threads beyond the system limits, which is roughly 2000 on my box. I tried your code with a really short lived thread: by using function void f() {}. This runs "forever". When running in a debugger, then setting a breakpoint, you will see no threads beyond the main running.
On Solaris 10, this example works just fine. I am just trying to say that behaviour on Windows is different from what one would observe on systems with pthreads, since storage for the *thread* can be reclaimed when that thread terminates(pthread_detach).
There is no detach on Windows, all threads are "detached" by default. There's no join either, you can wait for the thread to end if you like, but this is not required and has no effect on the "storage" for the thread, it's reclaimed either way.
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::vectorstd::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
participants (8)
-
Christian Henning
-
Howard Hinnant
-
Kevin Wheatley
-
Peter Dimov
-
Prashant Thakre
-
Rob Caldecott
-
Roland Schwarz
-
Sascha Seewald