views:

82

answers:

3

What is the best approach to achieve thread-safety for rather simple operations?

Consider a pair of functions:

void setVal(int val)
{
    this->_val = val;
}

int getVal() {
     return this->_val;
}

Since even assignments of primitive types aren't guaranteed to be atomic, should I modify every getter and setter in the program in the following way to be thread-safe?

void setVal(int val)
{
    this->_mutex.lock();
    this->_val = val;
    this->_mutex.unlock();
}

int getVal() {
     this->_mutex.lock();
     int result = this->_val;
     this->_mutex.unlock();
     return result;
}
+4  A: 

Are you using _val in multiple threads? If not, then no, you don't need to synchronize access to it.

If it is used from multiple threads, then yes, you need to synchronize access, either using a mutex or by using an atomic type (like std::atomic<T> in C++0x, though other threading libraries have nonstandard atomic types as well).

James McNellis
I wonder if it's really necessary if another thread doesn't matter what's returned by `getVal()`. For example if it only prints the result to the user in real time.
doc
+1  A: 

Mutexes are very costly, as they are able to be shared across processes. If the state that you're limiting access to is only to be constrained to threads within your current process then go for something much less heavy, such as a Critical Section or Semaphore.

OJ
A: 
int getVal() { 
     this->_mutex.lock(); 
     int result = this->_val; 
     this->_mutex.unlock(); 
     return result; 
}

What exactly are you hoping to accomplish with this? Sure, you've stopped this->_val from changing before you saved into result but it still may change before result is returned, -- or between the return and the assignment to whatever you assigned it -- or a microsecond later. Regardless of what you do, you are just going to get a snapshot of a moving target. Deal with it.

void setVal(int val)          
{          
    this->_mutex.lock();          
    this->_val = val;          
    this->_mutex.unlock();          
} 

Similarly, what is this buying you? If you call setVal(-5) and setVal(17) from separate threads at the same time, what value should be there after both complete? You've gone to some trouble to make sure that the first to start is also the first to finish, but how is that help to get the "right" value set?

James Curran
It's not about the value in this->_val. It's to protect _val from being rubish, because an assignment isn't atomic.I have used temporary in return to put the result on the stack so that another thread won't harm the value during return. Because I don't know if return's push is atomic(?). Since assignment isn't atomic I might get potentially a rubish in return. When the `result` variable is on the stack it won't be modified by another thread during return.
doc
In other words, without locks getVal() may return `-123232` between `setVal(-5)` and `setVal(17)` calls.
doc