分离线程中的竞争条件

Posted

技术标签:

【中文标题】分离线程中的竞争条件【英文标题】:Race Condition in detached Thread 【发布时间】:2019-03-01 11:13:34 【问题描述】:

我试图找到类似的问题,但找不到,或者我的知识不足以识别相似之处。

我有一个创建对象的主循环,而这个对象有一个无限循环来处理一个矩阵并用这个矩阵做一些事情。我在一个单独的线程中调用这个进程函数并对其进行分离,因此它能够多次处理矩阵,而主循环可能只是等待某些事情而不做任何事情。

一段时间后,主循环接收到一个新矩阵,而我只是通过创建一个新矩阵并将这个新矩阵传递给对象来表示它。这个想法是,由于在无限while循环中再次处理之前等待几秒钟,更新函数可以锁定互斥锁并且互斥锁不会(几乎)经常锁定。

下面我尝试编写一个最小的示例。

class Test
    
    public:
        Test();
        ~Test();

    void process()
        while(1)
             boost::mutes::scoped_lock locker(mtx);
             std::cout << "A" << std::endl;
             // do stuff with Matrix
             std::cout << "B" << std::endl;
             mtx.unlock();
             //wait for few microseconds
        
    

    void updateMatrix(matrix MatrixNew)
        boost::mutes::scoped_lock locker(mtx);
        std::cout << "1" << std::endl;
        Matrix = MatrixNew;
        std::cout << "2" << std::endl;
    

private:
    boost::mutex mtx;
    matrix Matrix;


int main()
Test test;
boost::thread thread_;

thread_ = boost::thread(&Test::process,boost::ref(test));
thread_.detach();

while(once_in_a_while)
    Matrix MatrixNew;
    test.updateMatrix(MatrixNew);


不幸的是,出现了竞争条件。 Process 和 Update 在锁定的互斥锁环境中有多个步骤,而我在这些步骤之间将内容打印到控制台。我发现,矩阵都搞砸了,字母/数字出现平行而不是连续的。

任何想法为什么会发生这种情况?

提前致以最良好的祝愿和感谢

【问题讨论】:

和问题无关,但是有没有可能是你忘记在updateMatrix里面解锁互斥锁了? 因为它是一个作用域锁,所以当锁被销毁时,互斥锁应该被解锁 【参考方案1】:
    while(1)
         boost::mutes::scoped_lock locker(mtx);
         std::cout << "A" << std::endl;
         // do stuff with Matrix
         std::cout << "B" << std::endl;
         mtx.unlock();
         //wait for few microseconds
    

在这里你手动解锁mtx。然后稍后某个时间scoped_lock(称为locker在其析构函数中解锁互斥锁(这是该类的重点)。我不知道保证的boost::mutex 要求什么,但解锁它的次数多于锁定它不会带来任何好处。

而不是 mtx.unlock();你大概想要locker.unlock();

编辑:这里的建议是避免为此使用 boost 并改用标准 c++。 threading 自 C++11(8 年!)以来一直是标准的一部分,所以大概你所有的工具现在都会支持它。使用标准化的代码/工具可以为您提供更好的文档和更好的帮助,因为它们更广为人知。我不是在抨击 boost(很多标准都是从 boost 开始的),但是一旦某些东西被消耗到标准中,你应该强烈考虑使用它。

【讨论】:

@DavideSpataro 我喜欢范围锁,因为它们提供了早期返回/异常安全性。我认为范围锁定是正确的工具,但实际上可能正确地确定范围(因此不需要任何手动解锁)最终是正确的做法。 @MikeVine 你是最棒的! locker.unlock() 做了这件事。非常感谢!

以上是关于分离线程中的竞争条件的主要内容,如果未能解决你的问题,请参考以下文章

Linux C++多线程同步的四种方式

无法理解或修复我的程序中的竞争条件

C# 多线程系列原子操作

如何动态锁定线程并避免竞争条件

跨线程合并更改时如何防止竞争条件?

JavaScript 中的竞争条件与复合赋值