C++ multithreading problem - is mutex the only way?
I have a counter variable which will be accessed by multiple threads which will increment/decrement it. It should not be updated by multiple threads at the same time.
I know that you can create a mutex object which has to be obtained before the variable in question can be changed. A critical section in this case is not appropriate because there are more than 1 function which can change the variable in question.
Is there another I can do this without using the mutex? Using a mutex does have a performance penalty (see http://www.codeguru.com/forum/showthread.php?t=333192). I believe that in Java, there is a key word you can use in the variable declaration to acc开发者_高级运维omplish that (is it called "synchronized"?), but is there such a thing in C++ at all?
I know that volatile is not the keyword I am looking for.
Thank you very much.
Most processors have 'atomic' increment and decrement instructions - in a large part, they are how mutexes are implemented at a machine level.
You can access these atomic instructions in your own code. Windows provides the InterlockedIncrement()
function, and glib provides equivalents. In x86 assembly language, you can use LOCK CMPXCHG
and kin directly.
C++ does not know anything about these concepts - you must use them yourself; there are no magic keywords for thread safety in C++.
See Atomic Instruction
While the use of atomic operations is probably the most efficient, the fact that this is used in more than one function is no bar to using a critical section in this or any other code - simply write a function:
void IncDec( bool inc ) {
EnterCritical Section( theCS );
if ( inc ) {
theVar++;
}
else {
thevar--;
}
LeaveCriticalSection( theCS );
}
and cal it from your other functions.
From the description, it sounds like maybe you only need InterlockedIncrement and the associated decrement function.
Edit - These are Windows functions ... I didn't stop to ask which platform.
A critical section in this case is not appropriate because there are more than 1 function which can change the variable in question.
This is a common scenario where critical sections are used, you need to assure every piece of code that access the variables do so while entering the same critical section(or mutex, or whichever guarding is used).
In Win32 IntelockedIncrement/IntelockedIncrement64 and associated operations compile to x86 instructions that allow processor level atomic operations on 32 or 64 bit words (depending on your architecture). This works fine in the case of a simple counter, but naturally won't work if your trying to synchronize a larger structure with multiple words.
PS from here, the corresponding asm you would need to implement this on a non Win32 system running on an x86.
inline long InterlockedExchangeAdd( long* Addend, long Increment )
{
long ret;
__asm__ (
/* lock for SMP systems */
"lock\n\t"
"xaddl %0,(%1)"
:"=r" (ret)
:"r" (Addend), "0" (Increment)
:"memory" );
return ret;
}
inline long InterlockedIncrement( long* Addend )
{
return InterlockedExchangeAdd( Addend, 1 );
}
inline long InterlockedDecrement( long* Addend )
{
return InterlockedExchangeAdd( Addend, -1 );
}
You could use atomic type for the counter variable - like sig_atomic_t (in GNU libc). Then there is no need for synchronization, since a race condition cannot happen, the operation on this variable is guaranteed to be atomic.
As others have mentioned, there's nothing in the current C++ standard that supports atomic variable access. If you're asking for C++ library support however (not entirely clear to me), there's an attempt-in-progress to mimic the upcoming C++ standard's atomic support here.
A critical section in this case is not appropriate because there are more than 1 function which can change the variable in question.
How will you know you have found all places the variable might be access if you don't create a single function using a critical section to modify it?
Additionally you will need to declare the variable volatile just make sure your compiler doesn't optimize any accesses to the variable inadvertently.
精彩评论