在运行之前获取 std::thread 的 thread:id?

Get std::thread's thread:id before it runs?

我正在尝试在 C++ 11 的 std::thread 之上构建一个线程安全层,其中每个对象都分配给一个拥有的线程,并且某些调用在用于错误的线程。拥有线程是唯一可以将对象传输到另一个线程的线程。

我已经全部正常工作了,除了,我找不到在线程实际 运行ning 之前获取线程的 thread::id 的方法。我需要在传递之前将新线程的 ID 附加到对象。

如果我用

std::thread newThread( [theObject]()
                       {
                           // use theObject here.
                       } );

我最早能得到线程的ID是在线程对象定义之后,此时线程已经运行ning.

我看到 std::thread 有一个默认的构造函数,但我看不出有什么方法可以在之后的线程上为 运行 提供一个函数。

有没有办法在线程上执行两步构建,或者在创建时控制线程的ID?

不——一创建线程,它就开始运行。如果你想在它做(大部分)任何事情之前获得它的 ID,你可能想要创建一个小包装器,你可以在其中传递线程(例如)一个 CV 和一个队列,它存放它的输出。

然后当线程启动时,它会检索自己的ID,将其存放在输出队列中,然后等待CV。当 parent 检索到 ID,并准备好让 child 开始做某事时,它会向 CV 发出信号,然后它就开始了。

与其在线程启动前获取线程 ID 运行,不如考虑让线程执行的函数在启动前进行一些初始设置。例如,您可以这样做:

bool isReady = false;
bool wasReceived = false;
std::mutex mutex;
std::condition_variable condition;

std::thread newThread([theObject, &isReady, &mutex, &condition] {
   /* Wait until we've been cleared to go. */
   std::unique_lock<std::mutex> lock(isReady);
   condition.wait(lock, [&isReady] { return isReady; });

   /* Signal that we're done. */
   wasReceived = true;
   lock.unlock();
   condition.notify_one();

   /* Put code here to do whatever it is that the thread should do. */
});

/* Read the thread's ID. It's currently waiting for us. */
auto id = newThread.get_id();

/* Tell the thread that we're ready for it. */
std::unique_lock<std::mutex> lock(mutex);
isReady = true;
condition.notify_one();

/* Wait until the thread has confirmed that it's ready. */
condition.wait(lock, [&] { return wasReceived; });

这将创建线程并让它等待创建者有机会读取其 ID。一旦发生这种情况,创建者就会等待线程确认它已准备就绪,然后您可以根据需要使用线程 ID。

当心上述代码中的错误 - 它完全未经测试。 :-)

通过传递唯一的 std::promise 参数启动每个非活动线程,首先获取线程 ID(线程 ID 用作传递引用参数)然后让它等待设置承诺由线程管理器。这也将消除使用条件变量的麻烦。

已编辑 片段

class smart_thread {
public:
    smart_thread(std::function<void(void)> task)
    {
        thread_ = std::thread([=]() {
            id_ = std::this_thread::get_id();
            // wait here till activated
            future_.get();
            if(active_) task();
        });
    }

    void activate()  {
        promise_.set_value();
        active_ = true;
    }

    ~smart_thread() {
        if(!active_) promise_.set_value();
        thread_.join();
    }    
private:
    std::thread::id id_;
    std::atomic<bool> active_ = false;
    std::thread thread_;
    std::promise<void> promise_;
    std::future<void> future_ = promise_.get_future();
};

void main()
{
    auto task = []() { std::cout << "Hello World\n"; };
    smart_thread thread(task); // start thread inactive mode
    thread.activate(); // activate thread
}

是否可以创建一个模板 class 以 std::function<void(T *object)> 的形式接受线程例程。如果需要传入额外的参数,这可以通过匿名闭包轻松完成。

template <class T>
class ThreadWrapper
{
public:
    ThreadWrapper(std::function<void(T *object)> function, T *object) :
    {
        m_thread = std::thread(WrapFunction, function, object);
        //optionally
        m_thread.detach();
    }
    static void WrapFunction(ThreadWrapper *wrapper, std::function<void()> function, T *object)
    {
        // Get the thread id and save in the object
        object->SetThreadId(get_id());
        // Now actually invoke the thread routine, with the id already installed.
        function(object);
    }
}

// Cleanup is left as an exercise for the reader.

当心上述代码中的错误 - 它完全未经测试。 :-) :-)