A Quick Question about Threads
Hi All I'm planning on replacing all our (Win32 API Wrapped) threads with the boost threads. I was looking at the thread class interface and there isn't a method to ask if the thread is still running. This is something we use quite a lot in out current wrapper. To get around this I was thinking of using a member variable in the function object that is passed to the thread constructor to indicated whether the thread had finished. Is there a better way? I've not had a really good look at the docs yet, but there doesn't appear to be a Critical Section class. Should I be using the Mutex for synchronisation instead? -- Regards Paul Paul Grenyer Email: pjgrenyer@iee.org Web: www.paulgrenyer.co.uk EvaneScence: http://www.evanescence.com
Paul Grenyer wrote:
I've not had a really good look at the docs yet, but there doesn't appear to be a Critical Section class. Should I be using the Mutex for synchronisation instead?
How do you think mutex and CS differ? From what I understand they perform the same purpose. Win32 CS's are recursive lockable, I believe that is an option or an ability of the boost mutex as well. I wouldn't be surprised if it was implemented as CS's in Win32. As for the "is running" query, I'm not sure. I have to admit I don't use boost threads (I have my own wrapper I made before I learned of boost), but I'm trying to help answering the simple question when I can ;). Jason
On Thu, 2003-07-31 at 19:48, Jason Winnebeck wrote: Hi
How do you think mutex and CS differ? From what I understand they perform the same purpose. Win32 CS's are recursive lockable, I believe that is an option or an ability of the boost mutex as well. I wouldn't be surprised if it was implemented as CS's in Win32.
I'm wasn't sure there was a difference. I've used Critical Sections before by not mutexes. If they're the same (or similar) so much the better! -- Regards Paul Paul Grenyer Email: pjgrenyer@iee.org Web: www.paulgrenyer.co.uk EvaneScence: http://www.evanescence.com
Generically, the difference between critical sections and mutexes is immense. In terms of implementation, one never knows. A critical section blocks EVERYTHING else in the process. A mutex only blocks things that are waiting on that particular mutex. If one is actually getting parallel processing (i.e. multi-processor machine), mutexes can be far more performant because only stuff that needs to block does - everything else keeps going. Critical sections are much easier to manage - in a way they're like a single global mutex. Deadlocks are much more difficult. Back in the day (NT 3.51), Windows was much more (two orders of magnitude) efficient with critical sections than with mutexes. That may no longer be true (I hope not, I'm using boost mutexes, now). Threading under Windows is not such a good idea anyway, with the exception of things that block anyway (e.g. I/O, client/server RPC, etc...). Windows doesn't deal well with more than two processors, so what's the point of having dozens of threads? They won't run in parallel anyway. State-based event engines tend to perform better than multithreading, although I find them nightmarish to debug. I have no clue what any other platform does. I'm hoping Linux scales to multiprocessor systems better, but while I've ported the code, I haven't run any tests, yet. Anyone have an 8-processor Linux box they want to loan me? - Mark Paul Grenyer wrote:
On Thu, 2003-07-31 at 19:48, Jason Winnebeck wrote:
Hi
How do you think mutex and CS differ? From what I understand they perform the same purpose. Win32 CS's are recursive lockable, I believe that is an option or an ability of the boost mutex as well. I wouldn't be surprised if it was implemented as CS's in Win32.
I'm wasn't sure there was a difference. I've used Critical Sections before by not mutexes. If they're the same (or similar) so much the better!
Mark Sizer wrote:
Generically, the difference between critical sections and mutexes is immense. In terms of implementation, one never knows.
A critical section blocks EVERYTHING else in the process. A mutex only blocks things that are waiting on that particular mutex.
Are you absolutely serious/sure about that? I've been using critical sections becauase I couldn't find a reason to use mutexes. So far I've only run my program on single processor machines (where it probably doesn't matter), but I'd hate to think I would have a huge amount of contention on multiprocessor machines. I can see how crit secs can be faster on a single CPU machine with those semantics, because when you schedule the process, you just decide to only schedule that thread. And on a single CPU just setting a flag should work and be safe to do. Jason
Jason Winnebeck wrote:
Mark Sizer wrote:
Generically, the difference between critical sections and mutexes is immense. In terms of implementation, one never knows.
A critical section blocks EVERYTHING else in the process. A mutex only blocks things that are waiting on that particular mutex.
Are you absolutely serious/sure about that? I've been using critical sections becauase I couldn't find a reason to use mutexes. So far I've only run my program on single processor machines (where it probably doesn't matter), but I'd hate to think I would have a huge amount of contention on multiprocessor machines.
I can see how crit secs can be faster on a single CPU machine with those semantics, because when you schedule the process, you just decide to only schedule that thread. And on a single CPU just setting a flag should work and be safe to do.
Jason
I wouldn't bet my life, or even a paycheck on it, but I'm pretty sure. It may be a distinction that some book made years ago that has stuck in my head. Here's MSDN's summary (not that I'm claiming MSDN is authoritative): http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/bas... <quote> Critical section objects provide synchronization similar to that provided by mutex objects, except that critical section objects can be used only by the threads of a single process. Event, mutex, and semaphore objects can also be used in a single-process application, but critical section objects provide a slightly faster, more efficient mechanism for mutual-exclusion synchronization (a processor-specific test and set instruction). Like a mutex object, a critical section object can be owned by only one thread at a time, which makes it useful for protecting a shared resource from simultaneous access. There is no guarantee about the order in which threads will obtain ownership of the critical section, however, the system will be fair to all threads. Unlike a mutex object, there is no way to tell whether a critical section has been abandoned. </quote> The efficiency issue implied here could be that mutexes can be named objects shared across PROCESSES, not just threads within a process. That would not apply to boost::mutexes - they're not named. The Win32 critical section API does seem to imply that there are more than one of them - otherwise why pass a pointer? A google search of "POSIX critical section" turned up the fact that POSIX mutexes are generally implemented under Windows as CriticalSections. It's looking like a case where the terms are interchangeable without a VERY specific context. It looks like I'm wrong :( - Mark P.S. I checked a couple of old textbooks I have on my bookshelf and I couldn't find the distinction I recall, either.
Mark,
You may be in good company here. There is a strong myth, that has been
running for years, that a Win32 critical section is a way of obtaining
*exclusive* use of the CPU. It's just plain wrong, but there are a
surprising number of folks who believe it. From that thought, on a
uniprocessor, everything else *would* stop when a thread entered a critical
section.
In a previous life you were likely unlucky enough to get exposed to someone
who told you this.
Best - Richard
----- Original Message -----
From: "Mark Sizer"
Jason Winnebeck wrote:
Mark Sizer wrote:
Generically, the difference between critical sections and mutexes is immense. In terms of implementation, one never knows.
A critical section blocks EVERYTHING else in the process. A mutex only blocks things that are waiting on that particular mutex.
Are you absolutely serious/sure about that? I've been using critical sections becauase I couldn't find a reason to use mutexes. So far I've only run my program on single processor machines (where it probably doesn't matter), but I'd hate to think I would have a huge amount of contention on multiprocessor machines.
I can see how crit secs can be faster on a single CPU machine with those semantics, because when you schedule the process, you just decide to only schedule that thread. And on a single CPU just setting a flag should work and be safe to do.
Jason
I wouldn't bet my life, or even a paycheck on it, but I'm pretty sure. It may be a distinction that some book made years ago that has stuck in my head.
Here's MSDN's summary (not that I'm claiming MSDN is authoritative):
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/bas...
<quote> Critical section objects provide synchronization similar to that provided by mutex objects, except that critical section objects can be used only by the threads of a single process. Event, mutex, and semaphore objects can also be used in a single-process application, but critical section objects provide a slightly faster, more efficient mechanism for mutual-exclusion synchronization (a processor-specific test and set instruction). Like a mutex object, a critical section object can be owned by only one thread at a time, which makes it useful for protecting a shared resource from simultaneous access. There is no guarantee about the order in which threads will obtain ownership of the critical section, however, the system will be fair to all threads. Unlike a mutex object, there is no way to tell whether a critical section has been abandoned. </quote>
The efficiency issue implied here could be that mutexes can be named objects shared across PROCESSES, not just threads within a process. That would not apply to boost::mutexes - they're not named.
The Win32 critical section API does seem to imply that there are more than one of them - otherwise why pass a pointer?
A google search of "POSIX critical section" turned up the fact that POSIX mutexes are generally implemented under Windows as CriticalSections.
It's looking like a case where the terms are interchangeable without a VERY specific context. It looks like I'm wrong :(
- Mark
P.S. I checked a couple of old textbooks I have on my bookshelf and I couldn't find the distinction I recall, either.
Info: http://www.boost.org Wiki: http://www.crystalclearsoftware.com/cgi-bin/boost_wiki/wiki.pl Unsubscribe: mailto:boost-users-unsubscribe@yahoogroups.com
Your use of Yahoo! Groups is subject to http://docs.yahoo.com/info/terms/
Mark Sizer wrote:
I wouldn't bet my life, or even a paycheck on it, but I'm pretty sure. It may be a distinction that some book made years ago that has stuck in my head.
Here's MSDN's summary (not that I'm claiming MSDN is authoritative): http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/bas...
It looks like you probably saw this already and changed your mind halfway throught he post, but did you read the last paragraph? <quote> When a critical section object is owned, the only other threads affected are those waiting for ownership in a call to EnterCriticalSection. Threads that are not waiting are free to continue running. </quote> Jason
Mark Sizer wrote: [...]
A critical section blocks EVERYTHING else in the process. [...] P.S. I checked a couple of old textbooks I have on my bookshelf and I couldn't find the distinction I recall, either.
I bet all my kids, a book was about OS/2 [RIP]. ;-) http://groups.google.com/groups?selm=3D52FB63.7B95E08%40web.de (Subject: Re: "memory location") regards, alexander. -- http://www.terekhov.de/russian-linux
Maybe it's a terminology thing. In Win32 the difference between a critical
section and a mutex is that a mutex is a system wide object (ie it is known
in other processes) and a critical section is only available to the threads
of one process.
A critical section can only block those threads that choose to Enter it in
the same way as a mutex can only block those threads that choose to Wait on
it.
I have not done any performance testing but one would expect critical
sections to perform better because they are (mostly) non-kernel code.
Best - Richard
----- Original Message -----
From: "Mark Sizer"
Generically, the difference between critical sections and mutexes is immense. In terms of implementation, one never knows.
A critical section blocks EVERYTHING else in the process. A mutex only blocks things that are waiting on that particular mutex.
If one is actually getting parallel processing (i.e. multi-processor machine), mutexes can be far more performant because only stuff that needs to block does - everything else keeps going. Critical sections are much easier to manage - in a way they're like a single global mutex. Deadlocks are much more difficult.
Back in the day (NT 3.51), Windows was much more (two orders of magnitude) efficient with critical sections than with mutexes. That may no longer be true (I hope not, I'm using boost mutexes, now). Threading under Windows is not such a good idea anyway, with the exception of things that block anyway (e.g. I/O, client/server RPC, etc...). Windows doesn't deal well with more than two processors, so what's the point of having dozens of threads? They won't run in parallel anyway. State-based event engines tend to perform better than multithreading, although I find them nightmarish to debug.
I have no clue what any other platform does. I'm hoping Linux scales to multiprocessor systems better, but while I've ported the code, I haven't run any tests, yet. Anyone have an 8-processor Linux box they want to loan me?
- Mark
Paul Grenyer wrote:
On Thu, 2003-07-31 at 19:48, Jason Winnebeck wrote:
Hi
How do you think mutex and CS differ? From what I understand they perform the same purpose. Win32 CS's are recursive lockable, I believe that is an option or an ability of the boost mutex as well. I wouldn't be surprised if it was implemented as CS's in Win32.
I'm wasn't sure there was a difference. I've used Critical Sections before by not mutexes. If they're the same (or similar) so much the better!
Info: http://www.boost.org Wiki: http://www.crystalclearsoftware.com/cgi-bin/boost_wiki/wiki.pl Unsubscribe: mailto:boost-users-unsubscribe@yahoogroups.com
Your use of Yahoo! Groups is subject to http://docs.yahoo.com/info/terms/
I just did this, it's remarkably easy. I then ported the system to Linux from Windows with no problems at all. Boost Threads rock. That being said... Be very careful about confusing object lifetime with thread lifetime. The relationship is murky, at best. I can start a thread on a stack based object. When that object goes out of scope, the thread does not stop. I can start a thread on a heap based object, when the thread terminates, the object is not deleted. That being said, I use the method you describe. Just make sure your object doesn't go out of scope or get deleted. I found the synchronization stuff strange, at first. Now I love it, it's much less error prone than critical sections or mutexes. You use a combination of mutexes and locks. The mutex is used only to acquire the lock, which is the only way to use the mutex. Locks, at least scoped_lock, release the mutex when they go out of scope. After much debate, we adopted the following coding standard: { boost::mutex::scoped_lock lock(_mtxShared); // do whatever } It makes it very clear what the locked section is, even if the "open brace then code on one line" is a bit strange. Also after much debate, we decided to never explicitly unlock. With this scoping convention, it's both redundant and obscuring (e.g. auto-release on an exception prior to the unlock call). I deleted tons of: try { critical_section.lock(); // do whatever critical_section.unlock(); } catch (...) { critical_section.unlock(); throw; } Have fun, - Mark Paul Grenyer wrote:
Hi All
I'm planning on replacing all our (Win32 API Wrapped) threads with the boost threads.
I was looking at the thread class interface and there isn't a method to ask if the thread is still running. This is something we use quite a lot in out current wrapper. To get around this I was thinking of using a member variable in the function object that is passed to the thread constructor to indicated whether the thread had finished. Is there a better way?
I've not had a really good look at the docs yet, but there doesn't appear to be a Critical Section class. Should I be using the Mutex for synchronisation instead?
On Thu, 2003-07-31 at 20:44, Mark Sizer wrote: Hi Mark
I just did this, it's remarkably easy. I then ported the system to Linux from Windows with no problems at all. Boost Threads rock. That being said...
Great! :-)
Be very careful about confusing object lifetime with thread lifetime. The relationship is murky, at best. I can start a thread on a stack based object. When that object goes out of scope, the thread does not stop. I can start a thread on a heap based object, when the thread terminates, the object is not deleted.
That being said, I use the method you describe. Just make sure your object doesn't go out of scope or get deleted.
Yes. I'd already got this far. :-) At the moment we use a system that involves inheriting from an object which creates the thread and overriding the method that is run in the thread. We have a variable number of threads in this particular application, which are stored in a container. This is easy because there is only one object to store. After looking at the boost thread stuff the only idea I've had so far is to store a structure in the container which has two members. One is the thread object the other is the thread. However, this idea doesn't feel right at the moment and I'm going to have to give it some more thought. Any suggestions would be greatly appreciated.
I found the synchronization stuff strange, at first. Now I love it, it's much less error prone than critical sections or mutexes.
Thanks for the pointers! I'll have a closer look at this stuff tomorrow at work. -- Regards Paul Paul Grenyer Email: pjgrenyer@iee.org Web: www.paulgrenyer.co.uk EvaneScence: http://www.evanescence.com
That being said, I use the method you describe. Just make sure your object doesn't go out of scope or get deleted.
Yes. I'd already got this far. :-)
At the moment we use a system that involves inheriting from an object which creates the thread and overriding the method that is run in the thread. We have a variable number of threads in this particular application, which are stored in a container. This is easy because there is only one object to store.
After looking at the boost thread stuff the only idea I've had so far is to store a structure in the container which has two members. One is the thread object the other is the thread. However, this idea doesn't feel right at the moment and I'm going to have to give it some more thought. Any suggestions would be greatly appreciated.
Unless you need to join the threads later, you can just ignore the boost::thread object. I let some of mine just go out of scope and nothing bad has happened, yet. I don't really like the thread objects because they're not comparable or copyable. I get why (there have been long discussions here about it), but it's still annoying. If you need to hold onto them, one easy way is to use a map with your objects as the key and a pointer to the thread object as the value. This means your threads shouldn't be on the stack. But since they're not copyable, you can't put them in the map directly. ThreadGroups are good for this, too. If you start all the threads in the same group, the group holds onto them. You can join the entire group in one call. It's quite convenient. My "doing" class that the thread runs is Handle/Body (it was and I didn't want to change it, I'm used to the patter). Therefore, I just do this to ramp them up: static void ReceiverBody::StartThreads( int iThreadCount) { for (int i = 0; i< iThreadCount; i++) { // handle on stack, but body is on allocated on heap Receiver recvr; // let the group hold onto the thread objects, I don't care _tgReceiveThreads.create_thread( recvr ); } } Where _tgReceiveThreads is a static boost::thread_group. Note that the thread entry-point functor is the handle, Receiver, not the body, ReceiverBody. void Receiver::operator()() { _pBody->Receive(); } To shut them all down: static ReceiverBody::StopThreads() { { boost::mutex::scoped_lock lockStop( _mutexStop ); _bStop = true; } _tgReceiveThreads.join_all(); } Where the threading loop inside is: void ReceiverBody::Receive() { bool bDone = bShuttingDown(); while (!bDone) { try { } catch ( errors ) { } bDone = bShuttingDown(); } } with this helper method: static bool ReceiverBody::bShuttingDown() { bool bLocalStop = false; { boost::mutex::scoped_lock lockStop( _mutexStop ); bLocalStop = _bStop; } return bLocalStop; } Note that this can't be const, even though it sort-of is. It modifies the mutex, even though that doesn't matter to the logical state of the object. Yes, I know this could be much shorter: static bool ReceiverBody::bShuttingDown() { { boost::mutex::scoped_lock lockStop( _mutexStop ); return _bStop; } } I don't like methods that leave out of the middle. The original is also easier to debug because you can set breakpoints that don't depend on the mutex state. However, that's another topic (see comp.lang.c++.moderated for an EXTENSIVE discussion on exiting methods - that's a very contentious bunch). _bStop is a static bool member. _mutexStop is a static boost::mutex member. Works great. - Mark
Mark Sizer wrote:
static bool ReceiverBody::bShuttingDown() { bool bLocalStop = false; { boost::mutex::scoped_lock lockStop( _mutexStop ); bLocalStop = _bStop; }
return bLocalStop; } Note that this can't be const, even though it sort-of is. It modifies the mutex, even though that doesn't matter to the logical state of the object.
Mark, a tip on that. I don't know if this applies to boost mutex or not, but if their system is like mine, then you can declare _mutexStop with the mutable keyword. Then you can declare the method bShuttingDown as const. At first it might seem like a bad thing, saying const when you really don't mean it, but I believe that for member functions const means that the state of the object does not change as a result of the function -- and it won't, because the state before and after is the same. Jason
Mark Sizer wrote:
After much debate, we adopted the following coding standard:
{ boost::mutex::scoped_lock lock(_mtxShared);
// do whatever
}
That standard is great. RAII is great and I love it. I'm not using boost threads, but I would have had I known about them at the time. I have working code so I'm not going to change it. I use exceptions in my program as well, so I use something that works (from that example) identical to the scoped_lock. I usually do something like: void Object::function() { LockMutex lock( mtx ); //whatever } Then it is exception and "return" safe. I have thought about using the style you give all of the time, but I only do it now if I must (because I want the mutex to lock early). The drawback is that you can't do something like this with the RAII methods. mtx.lock(); mtx2.lock(); mtx.release(); mtx2.release(); But I've never seen a case so far where I'm required to do that. I do have a LockMutexEx object that allows you to call release to release early. I make sure to use it as rarely as possible, but I've used it I believe once on a condition variable where I wanted to keep it locked if my condition was met. I doesn't sound like I'd need it when describing it here but I did use it once. I can see a problem with it since with RAII, you are supposed to "have the resource" while the object exists. Jason
Jason Winnebeck wrote:
The drawback is that you can't do
something like this with the RAII methods.
mtx.lock(); mtx2.lock(); mtx.release(); mtx2.release();
But I've never seen a case so far where I'm required to do that.
One use case for that that I'm aware of is when you want to have multiple concurrent searches/modifies in a tree datastructure. You can lock a parent node, scan the children nodes to find the one you want, lock the child and then release the parent so that another search can get to a sibling object before you are finished with the child node. -- Jonathan Biggar jon@floorboard.com jon@biggar.org
participants (6)
-
Alexander Terekhov
-
Jason Winnebeck
-
Jonathan Biggar
-
Mark Sizer
-
Paul Grenyer
-
Richard Howells