我是否应该使用互斥锁保护基本类型的操作,以便在C ++中具有线程安全性?

时间:2010-09-01 13:39:52

标签: c++ locking thread-safety mutex atomic

为相当简单的操作实现线程安全的最佳方法是什么?

考虑一对函数:

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

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

由于原始类型的赋值不能保证是原子的,我是否应该按照以下方式修改程序中的每个getter和setter以保证线程安全?

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 个答案:

答案 0 :(得分:6)

您是否在多个线程中使用_val?如果没有,那么不,你不需要同步访问它。

如果从多个线程使用它,那么是的,您需要使用互斥锁或使用原子类型(如C ++ 0x中的std::atomic<T>)来同步访问,尽管其他线程库具有非标准原子类型)。

答案 1 :(得分:1)

互斥体非常昂贵,因为它们可以跨进程共享。如果您限制访问的状态仅限于当前进程中的线程,那么请选择不那么重的东西,例如Critical Section或Semaphore。

答案 2 :(得分:1)

在32位x86平台上,在4字节边界上对齐的32位值的读取和写入是原子的。在64位平台上,您还可以依赖64位加载和8字节对齐值的存储也是原子的。 SPARC和POWER CPU也可以这样工作。

C ++没有做出这样的保证,但实际上没有编译器会搞乱它,因为每个非平凡的多线程程序都依赖于这种行为。

答案 3 :(得分:-3)

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

你到底想要完成什么?当然,在保存到this->_val之前,你已经停止了result的更改,但是在结果返回之前它仍然可能会发生变化,或者在返回和分配给你指定的任何内容之间 - 或者微秒后。无论你做什么,你只需要获得移动目标的快照。处理它。

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

同样,这对你有什么用?如果您同时从不同的线程中调用setVal(-5)setVal(17),那么完成后应该有什么值?你已经遇到了一些麻烦,以确保第一个开始也是第一个完成,但是如何帮助设置“正确”值?