返回原子,我应该在getter中使用临时线程安全吗?

时间:2010-09-03 19:21:52

标签: c++ multithreading thread-safety atomic getter

是否有必要在此使用临时线程安全?

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

我会给你反汇编简单的RAII测试函数

int test()
{
    RAIITest raii; //let's say it's a scoped lock
    return 3;
}


 {
     0x004013ce <_Z4testv>:    push  %ebp
     0x004013cf <_Z4testv+1>:  mov   %esp,%ebp
     0x004013d1 <_Z4testv+3>:  sub   $0x28,%esp
     return 3;
     0x004013d4 <_Z4testv+6>:  lea   -0x18(%ebp),%eax
     0x004013d7 <_Z4testv+9>:  mov   %eax,(%esp)
     0x004013da <_Z4testv+12>: call  0x4167a0 <_ZN8RAIITestD1Ev>  //here destructor is called
     0x004013df <_Z4testv+17>: mov   $0x3,%eax //here result is pushed onto the stack
 }
 0x004013e4 <_Z4testv+22>: leave 
 0x004013e5 <_Z4testv+23>: ret   

编译器是gcc / g ++ 3.4.5

4 个答案:

答案 0 :(得分:5)

如果this->_val同步对this->_mutex的访问,则您无法选择当前编写代码的方式。在解锁互斥锁之前,您需要阅读this->_val,并且必须在返回之前解锁互斥锁。 result变量是获得此操作顺序所必需的。

如果你在Boost中使用lock_guard(或scoped_lock),则不需要使用临时值,因为当函数返回时,互斥锁上的锁将被释放。例如,使用C ++ 0x线程库:

int getVal() {
    std::lock_guard<std::mutex> lock(_mutex);
    return this->_val;
}   // lock is released by lock_guard destructor 

答案 1 :(得分:1)

如果使用显式锁定()/ unlock(),则为是。否,如果您在堆栈上构造一个锁定对象并让其析构函数执行解锁。

答案 2 :(得分:0)

否 - 编译器自动为返回值创建临时值。您通常也不需要使用互斥锁保护读取,因此即使它是多线程的,只需return _val;即可。

顺便说一下,我已经摆脱了领先的下划线 - 关于什么变量名称,当它们以下划线开头时可以使用和不能使用的规则非常复杂,最好完全避免它们。

答案 3 :(得分:0)

你可以干净利落地完成这项工作,你的互斥锁被封装在一个scoped_lock中,可以在销毁时解锁:

 int getVal() {
       scoped_lock lockit(_mutex);
       return _val;
 }

是的,你需要保持锁定直到它被返回。