带静态互斥体的C ++类&比赛条件

时间:2016-10-20 21:33:50

标签: c++11

我将这个带有静态互斥锁的C ++类作为该类的私有成员,以保护该类的另一个公共函数中的cout。但是当我从两个线程调用该类的对象时,我得到了一个竞争条件。不确定为什么?

class ThreadSafePrint
{
  public:
      void myprint(int threadNumber)
      {
        std::lock_guard<std::mutex> gaurd(mymutex);
        cout <<"Thread " << threadNumber << endl;
      }
  private:
      static std::mutex mymutex;
};

std::mutex ThreadSafePrint::mymutex;


int main()
{
    ThreadSafePrint obj;

    std::vector<std::thread> workers;

    int threadNumber;
    // create 2 threads and pass a number 
    for(int i=0; i<2;++i)
    {
      // threadNumber = 0 for 1st thread
      if(i==0)
      {
          threadNumber = i;
      }
      // threadNumber = 1 for 2nd thread
      if(i==1)
      {
          threadNumber = i;
      }

      workers.push_back(std::thread([&obj,&threadNumber]()
      {
          obj.myprint(threadNumber);
      }));

    }

    // join all threads
    std::for_each(workers.begin(), workers.end(),[](std::thread & th)
    {
            th.join();
    });

    return 0;
    }

以下是一些结果:

>> ./mythreads
Thread 1
Thread 1
>> ./mythreads
Thread 0
Thread 0

3 个答案:

答案 0 :(得分:2)

您在两个工作线程中捕获对局部变量threadNumber的引用,在两个线程中访问它,并在主线程中将其变更而不进行任何同步。这确实是竞争条件。相反,按价值捕获。

 workers.push_back(std::thread([&obj, threadNumber]() 

答案 1 :(得分:0)

您必须按值捕获threadNumber,而不是按引用捕获。

交换:

workers.push_back(std::thread([&obj,&threadNumber]()

通过

workers.push_back(std::thread([&obj,threadNumber]()

否则,第二个循环运行也会对第一个线程更改变量threadNumber

#include <iostream>
#include <thread>
#include <mutex>
#include <vector>
#include <algorithm>

class ThreadSafePrint
{
    public:
        void myprint(int threadNumber)
        {
            std::lock_guard<std::mutex> gaurd(mymutex);
            std::cout <<"Thread " << threadNumber << std::endl;
        }
    private:
        static std::mutex mymutex;
};

std::mutex ThreadSafePrint::mymutex;


int main()
{
    ThreadSafePrint obj;

    std::vector<std::thread> workers;

    int threadNumber;
    // create 2 threads and pass a number 
    for(int i=0; i<2;++i)
    {
        // threadNumber = 0 for 1st thread
        if(i==0)
        {
            threadNumber = i;
        }
        // threadNumber = 1 for 2nd thread
        if(i==1)
        {
            threadNumber = i;
        }

        workers.push_back(std::thread([&obj,threadNumber]()
        {
            obj.myprint(threadNumber);
        }));

    }

    // join all threads
    std::for_each(workers.begin(), workers.end(),[](std::thread & th)
    {
        th.join();
    });

    return 0;
}

答案 2 :(得分:0)

当您创建线程时,您明确要求编译器为线程提供对主函数/线程正在使用的变量threadNumber的相同实例的访问权。

[&threadNumber]

再次:这是一个明确的分享。

事实上,您的代码表明您可能希望在尝试使用线程之前更好地掌握语言,这段代码非常奇怪:

int threadNumber;
// create 2 threads and pass a number 
for(int i=0; i<2;++i)
{
  // threadNumber = 0 for 1st thread
  if(i==0)
  {
      threadNumber = i;
  }
  // threadNumber = 1 for 2nd thread
  if(i==1)
  {
      threadNumber = i;
  }

目前还不清楚为什么任何人会写这个而不是:

for (int i = 0; i < 2; ++i) {
    workers.push_back(std::thread([&obj, i] () {
      obj.myprint(threadNumber);
    }));
}

即使这仍然有许多设计上的怪异 - 为什么你通过引用传递obj?这是一个带有一个静态成员的空类,您可以轻松避免捕获和写入:

for (int i = 0; i < 2; ++i) {
    workers.emplace_back([] (int threadNumber) {
        ThreadSafePrint obj;
        obj.myprint(threadNumber);
    }, i);  // pass `i` -> `threadNumber`
}