multithreading - 使用锁保护和互斥锁的首选方法是什么

标签 multithreading locking mutex c++17

类成员函数将在其mutexlock_guard上使用critical sectioncritical data。我可以看到这可以通过2种不同的方式来完成。

情况1:-for循环内部。 lock_guard在每次迭代时进行构造和破坏。

std::mutex s_mutex;

class Foo {
public:
    void bar() {
        for ( ... ) {
            std::lock_guard<std::mutex> guard( s_mutex );
            // critical section data
        } // lock_guard goes out of scope and releases or unlocks mutex
    }
};

情况2:-for循环之外。 lock_guard创建一次,然后在循环完成后销毁。
std::mutex s_mutex;

class Foo {
public:
    void bar() {
        std::lock_guard<std::mutex> guard( s_mutex );
        for ( ... ) {
            // data
        }
    } // lock_guard goes out of scope releasing or unlocking mutex.
};

我确实知道,在第一种情况下,一个线程可以在一个迭代中访问循环,而另一个线程可以在不同的迭代中访问循环,但是没有两个线程可以同时访问关键部分。至于第二种情况,我确实知道,如果某个线程正在访问该循环,则第二个线程只有在完全完成之前才能接触该循环。

一种方法比另一种方法更可取,还是取决于使用目的?是否会对性能产生影响?只需要澄清一些尝试维护现代c++最佳实践的方法即可。

最佳答案

您要解锁互斥锁,然后立即将其锁定。发生的情况取决于互斥锁的实现方式,但是典型的不公平实现会唤醒一个等待的线程,但是会在该线程能够运行之前抢占互斥锁,从而浪费了执行时间。

如果您的互斥量实现是公平的(请考虑ticket lock),那么您的线程将无法在解锁互斥量后将其锁定,而必须等到另一个线程离开关键部分。这意味着在争用状态下,您的线程将不得不在每次迭代时进行上下文切换,从而浪费了执行时间。

因此,第二种情况(循环外部的互斥体)在公平和不公平的互斥体实现中都应该更有效,这是您应该做的。

现在,如果您关心延迟,则可以考虑在每次迭代时都锁定互斥锁,因为这允许其他线程运行,但这仅对于公平的互斥锁实现才有意义。

C++并没有说明std::mutex是否公平,而且大多数实现都不公平。因此,不要对此抱有太大期望。

因此,唯一明智且可移植的方法是将锁置于循环之外。因为即使您担心延迟,std::mutex也不会对您有所帮助。

关于multithreading - 使用锁保护和互斥锁的首选方法是什么,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49666630/

相关文章:

c++ - 使用正在进行的函数调用销毁对象

c++ - 使用线程根据起始字符打印出单词

python - 如何在正在运行的 python 脚本中启动其他脚本(新线程或进程?)

mysql - MySQL RENAME 和 CREATE TABLE 语句冲突的问题

.net - 如何强制 Powershell 脚本等待覆盖文件,直到另一个进程完成读取该文件?

multithreading - 在 std::lock_guard<> 的声明中添加 const 有什么意义?

c++ - 我应该为不同的对象使用不同的互斥量吗?

c# - new Thread() 和垃圾回收

c# - 对父线程中的变量评估感到困惑

java - 偏向锁定设计决策