c++ 11中的线程

Threads in C++11

本文关键字:线程 c++      更新时间:2023-10-16

我正在把我的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习惯用法重新设计的方法。

使用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;
    }
}

我所知道的关于c++ 11并发性的最佳参考/学习书籍是:Anthony Williams的《c++ concurrency in Action: Practical多线程》。

main()函数中有一个竞争条件(虽然不是"数据竞争"),我在下面转录、内联和简化了它:

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恰好在主线程再次调度之前运行到完成,那么该断言将失败。由于标准不限制调度,如果您需要工作线程等待,则需要编写一些代码来阻塞。