如何使用锁来防止竞争条件

时间:2016-11-22 14:24:36

标签: c++ multithreading

我的代码中有一个错误,我发现这是一个竞争条件。我知道这是一种竞争条件,因为它会间歇性地发生。我研究了如何防止这些竞争条件,我遇到了这个

      for ( int i = 0; i < 10000000; i++ )
      {
           //lock x
           x = x + 1; 
           //unlock x
      }

有人可以详细说明我如何实现这些锁吗?

2 个答案:

答案 0 :(得分:4)

您的示例建议,您在线程中要执行的操作是对int变量的操作。如果确实如此,正如其他人所指出的那样,std::atomic可能是实现它的最简单方法。

#include <thread>
#include <atomic>
#include <iostream>

std::atomic<int> x = 0;

void increment()
{
    for(int i = 0; i < 10000000; ++i)
    {
        ++x;
    }
}

int main()
{
    std::thread t1(increment);
    std::thread t2(increment);

    t1.join();
    t2.join();

    std::cout << x;
}

但是,为了保护更复杂的操作不会同时在多个线程中执行,您应该使用std::lock_guard。它使用RAII(资源获取是初始化)原则来锁定互斥锁的生命周期。

#include <thread>
#include <mutex>
#include <iostream>

int x = 0;
std::mutex mtx;

void increment()
{
    for ( int i = 0; i < 10000000; i++ )
    {
        std::lock_guard<std::mutex> lock(mtx); //lock mtx
        ++x;

        // mtx is automatically released when lock
        // goes out of scope -> RAII
    }
}

int main()
{
    std::thread t1(increment);
    std::thread t2(increment);

    t1.join();
    t2.join();

    std::cout << x;
}

修改

根据您的评论,这是另一个例子:

#include <thread>
#include <mutex>
#include <iostream>

class Foo
{
public:
    void increment()
    {
        for ( int i = 0; i < 10000000; ++i )
        {
            std::lock_guard<std::mutex> lock(mtx); //lock mtx
            ++x;

            // mtx is automatically released when lock
            // goes out of scope -> RAII
        }
    }

    void decrement()
    {
        for ( int i = 0; i < 10000000; ++i )
        {
            std::lock_guard<std::mutex> lock(mtx); //lock mtx
            --x;

            // mtx is automatically released when lock
            // goes out of scope -> RAII
        }
    }

    static int x;
    static std::mutex mtx;
};

int Foo::x = 0;
std::mutex Foo::mtx;

int main()
{
    std::thread t1(&Foo::increment, Foo());
    std::thread t2(&Foo::decrement, Foo());

    t1.join();
    t2.join();

    std::cout << Foo::x;
}

答案 1 :(得分:2)

  

我知道这是一种竞争条件,因为它会间歇性地发生

虽然竞赛条件通常会间歇性地发生,但还有其他类型的错误具有相似的行为,因此您的推理并不能保证准确。也就是说,在没有看到程序的情况下,确定在具有多个线程的程序中这是一个非常可能的问题。

  

有人可以详细说明我如何实现这些锁吗?

互斥锁无法在C ++中实现。它们通常使用机器指令Test-and-set实现。

但是,您自己并不需要实施锁定。从C ++ 11开始,标准库已经包含了一个实现。更好的是,它包含更高级别的原子类型(std::atomic),它们提供原子访问而不显式锁定执行(原子类型的实现甚至可以使用更有效的指令来避免锁定,具体取决于目标架构)。 p>

如果您的标准库已过时,则可以使用操作系统提供的线程API。它几乎肯定会为您提供某种互斥结构。