在线程结束时调用 detach()

Calling detach() at the end of the thread

我有一个类似于以下代码的工作线程。在begin_work中,它会在创建新的工作线程之前检查工作线程是否正在执行。但是,begin_work 永远不会在当前线程退出时创建下一个工作线程,直到我调用 end_work.

我尝试在线程末尾调用 detach,它工作正常。在线程末尾调用 detach 是否安全?或者,如何在调用 begin_work 之前不调用 end_work 来安全地创建下一个工作线程?

class thread_worker {
private:
    std::thread worker;
    // ... other menbers

public:
    thread_worker() {};
    ~thread_worker() { end_work(); };

    void begin_work() {
        if (!worker.joinable()) {
            worker = std::thread { &thread_worker::do_work, this };
        }
    }

    void do_work() {
        // ... access other members ...

        if (exit not by notify) {
            worker.detach();    // can I call detach?
        }
    }

    void end_work() {
        if (worker.joinable()) {
            // notify worker to exit
            worker.join();
        } 
    }
};

编辑:

我的目的是无阻塞地调用 begin_work。如果有一个正在执行的工作线程,那么该函数将 return 直接或 return 一个 is_working 错误。否则,无缝地创建一个新的工作线程。

因为 std::thread::joinable() 总是 returns true 直到 joindetach 被调用。因此,即使当前工作线程已经退出,以后对 begin_work 的调用也永远不会创建新的工作线程。

因此,我需要一种在线程结束时自动分离的机制。

I have tried to call detach at the end of the thread and it works fine

在访问 worker 时存在 数据竞争 - 这是未定义的行为。当 begin_work 测试 worker.joinable() 时,do_work 可能会同时分离它(对 worker.detach() 的调用)。

您可以改为在创建时立即分离:

worker = std::thread { &thread_worker::do_work, this };
worker.detach();

但是,这可以同时留下多个线程 运行,这与您一次 运行 一个工作线程的要求相矛盾(但为什么只有一个?这只会让线程变得毫无意义) .

相反,您可以这样做:

void begin_work() {
    end_work();
    worker = std::thread { &thread_worker::do_work, this };
} 

确保上一个线程完成。


根据您的编辑,您只需要检查是否可以 加入 无需等待 - 这似乎是您想要分离的原因。您可以改为使用原子标志来做到这一点。基本上,您只需处理上面提到的 数据竞争

class thread_worker {
private:
    std::thread worker;
    std::atomic_bool w_done {true};
    
    // ... other menbers

public:
    thread_worker() {};
    ~thread_worker() { end_work(); };

    void begin_work() {
        if (w_done) {
            end_work();   
            worker = std::thread { &thread_worker::do_work, this };
        }
    }

    void do_work() {
        // ... access other members ...

        w_done = true;
    }

    void end_work() {
        w_done = false;
        if (worker.joinable()) {
            // notify worker to exit
            worker.join();
        } 
    }
};