Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/126.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 什么时候具有互斥的getter和setter是线程安全的?_C++_Multithreading_Pthreads - Fatal编程技术网

C++ 什么时候具有互斥的getter和setter是线程安全的?

C++ 什么时候具有互斥的getter和setter是线程安全的?,c++,multithreading,pthreads,C++,Multithreading,Pthreads,考虑以下类别: class testThreads { private: int var; // variable to be modified std::mutex mtx; // mutex public: void set_var(int arg) // setter { std::lock_guard<std::mutex> lk(mtx); var = arg; } int get_var()

考虑以下类别:

class testThreads
{
private:
    int var; // variable to be modified
    std::mutex mtx; // mutex
public:
    void set_var(int arg) // setter
    {
        std::lock_guard<std::mutex> lk(mtx);
        var = arg;
    }

    int get_var() // getter
    {
        std::lock_guard<std::mutex> lk(mtx);
        return var;
    }

    void hundred_adder()
    {
        for(int i = 0; i < 100; i++)
        {
            int got = get_var();
            set_var(got + 1);
            sleep(0.1);
        }
     }
};
类测试线程
{
私人:
int var;//要修改的变量
std::mutex mtx;//互斥
公众:
void set_var(int arg)//setter
{
标准:锁紧装置lk(mtx);
var=arg;
}
int get_var()//getter
{
标准:锁紧装置lk(mtx);
收益var;
}
无效百加器()
{
对于(int i=0;i<100;i++)
{
int get=get_var();
设置变量(got+1);
睡眠(0.1);
}
}
};
当我在main()中创建两个线程时,每个线程都有一个线程函数
hundu adder
修改相同的变量var,var的最终结果总是不同的,即不是200而是其他一些数字

从概念上讲,为什么在getter和setter函数中使用互斥锁不是线程安全的?锁紧防护装置是否未能阻止var的竞争条件?还有什么替代方案

Thread a: get 0
Thread b: get 0
Thread a: set 1
Thread b: set 1
瞧,var是1,尽管它应该是2

显然,您需要锁定整个操作:

for(int i = 0; i < 100; i++){
     std::lock_guard<std::mutex> lk(mtx);
     var += 1;
}
for(int i=0;i<100;i++){
标准:锁紧装置lk(mtx);
var+=1;
}
或者,您可以使变量原子化(在您的情况下,即使是宽松的变量也可以)

瞧,var是1,尽管它应该是2

显然,您需要锁定整个操作:

for(int i = 0; i < 100; i++){
     std::lock_guard<std::mutex> lk(mtx);
     var += 1;
}
for(int i=0;i<100;i++){
标准:锁紧装置lk(mtx);
var+=1;
}

或者,您可以使变量原子化(在您的情况下,即使是宽松的变量也可以)。

代码在线程安全中显示,从某种意义上讲,它永远不会设置或获取变量的部分值

但您对这些方法的使用并不能保证值会正确更改:多线程的读写可能会相互冲突。两个线程都读取值(11),都增加值(到12),然后都设置为相同的值(12)——现在您计算了2,但实际上只增加了一次

修复选项:

  • 提供“安全增量”操作
  • 提供等效值,以确保您正在更新的值与原始值相对应,并根据需要重试
  • 将调用代码包装到单独的互斥锁中,或者使用其他同步机制来防止操作混合

代码在线程安全中显示,从某种意义上讲,它永远不会设置或获取变量的部分值

但您对这些方法的使用并不能保证值会正确更改:多线程的读写可能会相互冲突。两个线程都读取值(11),都增加值(到12),然后都设置为相同的值(12)——现在您计算了2,但实际上只增加了一次

修复选项:

  • 提供“安全增量”操作
  • 提供等效值,以确保您正在更新的值与原始值相对应,并根据需要重试
  • 将调用代码包装到单独的互斥锁中,或者使用其他同步机制来防止操作混合
您的
get\u var()
set\u var()
本身是线程安全的。但是
get\u var()
后跟
set\u var()
的组合序列不是。没有保护整个序列的互斥锁

您有多个并发线程执行此操作。您有多个线程调用
get\u var()
。第一个线程完成并解锁互斥锁后,另一个线程可以立即锁定互斥锁,并获得与第一个线程相同的
get
值。没有任何东西可以阻止多个线程同时锁定和获取相同的
get

然后两个线程都将调用
set\u var()
,将受互斥保护的
int
更新为相同的值

这只是这里可能发生的一种可能性。您可以很容易地让多个线程按顺序获取互斥锁,从而将
var
增加几个值,然后紧跟着另一个暂停的线程,该线程在几秒钟前调用了
get\u var()
,现在才开始调用
set\u var()
,因此,将
var
重置为更小的值

您的
get\u var()
set\u var()
本身是线程安全的。但是
get\u var()
后跟
set\u var()
的组合序列不是。没有保护整个序列的互斥锁

您有多个并发线程执行此操作。您有多个线程调用
get\u var()
。第一个线程完成并解锁互斥锁后,另一个线程可以立即锁定互斥锁,并获得与第一个线程相同的
get
值。没有任何东西可以阻止多个线程同时锁定和获取相同的
get

然后两个线程都将调用
set\u var()
,将受互斥保护的
int
更新为相同的值


这只是这里可能发生的一种可能性。您可以很容易地让多个线程按顺序获取互斥锁,从而将
var
增加几个值,然后紧跟着另一个暂停的线程,该线程在几秒钟前调用了
get\u var()
,现在才开始调用
set\u var()
,因此,将
var
重置为更小的值。

为什么不对共享数据(本例中为var)使用std::atomic呢?这将更加安全高效。

为什么不对共享数据使用std::atomic(在本例中为var)?这样会更安全有效。

这绝对是经典之作。 一个线程获得
var
的值,释放
mutex
,另一个线程在第一个线程有机会更新它之前获得相同的值

因此
void testThreads::inc_var(){
    std::lock_guard<std::mutex> lk(mtx);
    ++var;
}
bool testThreads::compare_and_inc_var(int val){
    std::lock_guard<std::mutex> lk(mtx);
    if(var!=val) return false;
    ++var;
    return true;
}

Then write code like:

   int val;
   do{
       val=get_var();
   }while(!compare_and_inc_var(val));