我正在将我的C ++技能更新为C ++ 11。我是线程,总是一个问题区域。考虑一下这个测试代码:
// threaded.h
class MyThreadedClass
{
public:
MyThreadClass();
bool StartThread();
bool IsThreadDone();
inline void WorkThread();
private:
std::thread* workThread;
atomic<bool> threadDone;
}
// threaded.cpp
MyThreadedClass::MyThreadedClass() {
workThread = nullptr;
threadDone.store(true);
}
bool MyThreadedClass::StartThread() {
if (!threadDone.load()) { return false; }
threadDone.store(false);
workThread = new std::thread(&MyThreadedClass:WorkThread, this);
workThread->detach();
return true;
}
bool MyThreadedClass:IsThreadDone() {
return threadDone.load();
}
inline void MyThreadedClass::WorkThread() {
while (some_condition) { /*Do work*/ }
threadDone.store(true);
}
// main.cpp
int main() {
MyThreadedClass testInstance;
testInstance.StartThread();
for (int x = 0; x < 10; x++) {
do {
// This is sometimes true:
if (testInstance.StartThread()) { return 1;}
} while (!testInstance.IsThreadDone())
}
return 0;
}
我想看看这种类型代码的最坏情况,因此我在主要等待线程终止时不断地敲击它。有时会触发main中的故障情况。与许多线程问题一样,它不一致,因此不容易调试。
使用了threadDone变量,因为我在实际代码中访问了一个文件,并且不希望多个线程访问同一个文件。
深入了解我所缺少的内容或使用C ++ 11习惯用法重新设计此内容的方法。
答案 0 :(得分:0)
我对C ++ 11并发性的最佳参考/学习书是:Anthony C++ Concurrency in Action: Practical Multithreading。
答案 1 :(得分:0)
使用 std :: mutex 而不是 std :: atomic ,实现非常简单。
class MyThreadedClass
{
std::mutex _mutex;
std::unique_ptr<std::thread> _thread;
bool _done{false};
public:
MyThreadClass() = default;
bool StartThread()
{
std::lock_guard<std::mutex> lock(_mutex);
if (_thread || _done) return false;
_thread = std::make_unique<std::thread>(&MyThreadedClass, this);
return true;
}
bool IsThreadDone()
{
std::lock_guard<std::mutex> lock(_mutex);
return _done;
}
void WorkThread()
{
// do some work
std::lock_guard<std::mutex> lock(_mutex);
_done = true;
}
}
答案 2 :(得分:0)
您的main()
函数中存在竞争条件(虽然不是&#34;数据竞赛&#34;),我已在下面转录,内联和简化:
void MyThreadedClass::WorkThread() {
threadDone.store(true);
}
int main() {
MyThreadedClass testInstance;
testInstance.threadDone.store(false);
new std::thread(&MyThreadedClass::WorkThread, &testInstance)->detach();
// This sometimes fails:
assert(!testInstance.threadDone.load());
return 0;
}
如果在重新安排主线程之前WorkThread碰巧运行完成,那么断言将失败。由于标准不会限制调度,因此如果需要工作线程等待,则需要编写一些代码来阻止。