views:

511

answers:

8

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 accomplish 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.

+3  A: 

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.

Mark Wilkins
So there is nothing you can put in front of a variable declaration which specifies that it has to be accessed in an atomic fashion? I know that const, mutable and volatile are C++ qualifier words but they do not fit the bill.
Andy
@Andy No there isn't. The current C++ Standard does not address threading at all.
anon
Thank you very much.
Andy
+8  A: 

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 http://stackoverflow.com/questions/1762148/atomic-instruction/1762179#1762179

Will
A: 

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.

zacsek
`sig_atomic_t` has atomic writes (i.e. you don't need to worry about only 3 bytes of the variable being updated before a context switch) but not atomic increment/decrement. See this question: http://stackoverflow.com/questions/1762148/atomic-instruction
finnw
+2  A: 

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 );
}
Doug T.
+4  A: 

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.

anon
The qt library has a nice implementation of atomic operations http://doc.trolltech.com/4.3/atomic-operations.html
Jay
+3  A: 

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).

nos
A: 

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.

Cwan
Thank you. C++ does have something to make a variable local to a thread - declspec(thread) but it is probably specific to the Windows platform.
Andy
@Andy: __declspec(thread) makes variables thread-affine - meaning that they can't be shared between threads (well, at least not without violating their purpose).
Cwan
@Andy: Oh, and __declspec(thread) isn't windows-specific, it's VC++ specific.
Cwan
Thank you very much.
Andy
A: 

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.

jmucchiello