return 是原子的吗?我应该在 getter 中使用临时值以保证线程安全吗?

发布于 2024-09-17 11:03:39 字数 922 浏览 3 评论 0原文

这里是否需要使用临时变量来保证线程安全?

 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

Is it necessary to use a temporary here to be thread-safe?

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

I'll give you disassembly of simple RAII test function

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   

the compiler is gcc/g++ 3.4.5

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

君勿笑 2024-09-24 11:03:39

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

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

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

If access to this->_val is synchronized by this->_mutex, then you don't have a choice the way the code is written currently. You need to read this->_val before you unlock the mutex and you have to unlock the mutex before you return. The result variable is necessary to get this order of actions.

If you use a lock_guard (or scoped_lock in Boost), then you don't need to use the temporary because the lock on the mutex will be released when the function returns. For example, using the C++0x threads library:

int getVal() {
    std::lock_guard<std::mutex> lock(_mutex);
    return this->_val;
}   // lock is released by lock_guard destructor 
深爱成瘾 2024-09-24 11:03:39

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

Yes if you use explicit lock()/unlock(). No if you construct a lock object on the stack and have its destructor do the unlock.

掐死时间 2024-09-24 11:03:39

否——编译器会自动为返回值创建一个临时值。通常也不需要使用互斥锁来保护读取,因此即使它是多线程的,只需 return _val; 就足够了。

顺便说一句,我会去掉前导下划线——当变量名以下划线开头时可以使用和不能使用哪些变量名的规则足够复杂,最好完全避免它们。

No -- the compiler creates a temporary for the return value automatically. You don't normally need to protect a read with a mutex either, so even though its multithreaded, just return _val; should be sufficient.

As an aside, I'd get rid of the leading underscore though -- the rules about what variable names you can and cannot use when they start with an underscore are sufficiently complex that it's better to just avoid them entirely.

病毒体 2024-09-24 11:03:39

您可以干净地做到这一点,因为您的互斥体被封装在一个在销毁时解锁的作用域锁中:

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

是的,您确实需要持有锁直到它返回。

You can do this cleanly is your mutex is encapsulated in a scoped_lock that unlocks on destruction:

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

And yes, you do need to hold the lock until it's returned.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文