我将这个带有静态互斥锁的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
答案 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`
}