多个变量的多个互斥体

时间:2019-01-31 23:13:44

标签: c++ multithreading locking mutex

基于previous question

我对线程之间共享的不同变量做了一些冗长的分配。将这些分配拆分到单个作用域中以防止单个lock_guard占用所有变量是否有意义?

如果前一个线程移至第二个作用域,则下一个线程可以使用第一个变量。

我的猜测是,这取决于调用函数的复杂性。如果您只有一个任务,那肯定比第二个lock_guard锁定/解锁另一个互斥锁要快。

伪代码

// all used variables beside the lock_guards are created and initialized somewhere else

// do something ...

{
    std::lock_guard<std::mutex> lock(mut0);
    shared_var0 = SomeFunctionTakingSameTime0();  
}

{
    std::lock_guard<std::mutex> lock(mut1);
    shared_var1 = SomeFunctionTakingSameTime1();  
}

// do this again or other stuff ...

这种类型的代码结构可能有什么优点或缺点?

2 个答案:

答案 0 :(得分:1)

根据您的描述,我认为SomeFunctionTakingSameTime0()有点耗时。但是,与共享变量交互的唯一方法是赋值。因此,最好执行以下操作:

auto temp = SomeFunctionTakingSameTime0();
{
    std::lock_guard<std::mutex> lock(mut0);
    shared_var0 = std::move(temp);  
}

由于您为锁提供了两个不同的互斥体mut0mut1,所以最好的办法是分别获取它们。

答案 1 :(得分:1)

  

将这些分配拆分到单个作用域中以防止单个lock_guard占用所有变量是否有意义?

是的。确实,您的直觉是正确的。

  

这种类型的代码结构可能有什么优点或缺点?

但是,用一小段代码就无法预测这种情况。最好的建议是执行一些基准测试。

我个人会考虑一些重要方面:

  • shared_var0的类型?
  • 锁定互斥锁的时间>完成SomeFunctionTakingSameTime1的时间?

如您所说,如果您的函数SomeFunctionTakingSameTime0SomeFunctionTakingSameTime1将花费相当多的时间,那么分成两个不同的作用域可以帮助最大化吞吐量。

>

通常,关键部分(即您持有锁的范围)应尽可能短。

当然,像其他所有东西一样,需要权衡取舍。 lock / unlock操作不是免费的。

int shared; 
lock(mutex);
shared = 1;
unlock(mutex);

lock(mutex);
shared = 2;
unlock(mutex);

当然,这是一个愚蠢的例子。但这显示了锁定获取操作中的关键方面。 该示例中的赋值操作比两次锁定互斥锁便宜得多! 此外,这将阻止某些编译器优化(从语义的角度来看,可以完全删除赋值shared = 1)。

最后,如果shared_var0shared_var1的类型是基本类型(intfloat等),您甚至可以考虑将它们存储到{ {1}},并完全避免互斥。

相关问题