【问题标题】:How stall a spawned thread long enough for spawning thread to do something?如何使生成的线程停止足够长的时间以使生成线程执行某些操作?
【发布时间】:2012-06-25 03:27:27
【问题描述】:

Another SO thread 解释了如何使用thread::native_handle 来做 C++ 线程 API 之外的事情(例如,设置线程的优先级)。要点是:

std::thread t(functionToRun);
auto nh = t.native_handle());
// configure t using nh           

这种方法的问题在于,functionToRun 可能会在配置 t 的代码完成之前执行任意时间(包括完成)。

我相信我们可以通过以下方式防止这种情况发生(未经测试):

std::atomic<bool> configured(false);

std::thread t([&]{ while (!configured);   // spin until configured is true
                   functionToRun(); });
auto nh = t.native_handle();
// configure t using nh
configured = true;

不幸的是,这会导致生成的线程旋转等待configured 变为真。生成的线程最好在配置完成之前阻塞。

实现这一点的一种方法似乎是使用互斥体(也未经测试):

std::mutex m;

std::unique_lock<std::mutex> lock(m);

std::thread t([&]{ std::lock_guard<std::mutex> lg(m);   // block until m available
                   functionToRun(); });
auto nh = t.native_handle();
// configure t using nh
lock.unlock();                                          // allow t to continue

这似乎应该可行,但是从概念上讲,condvar 似乎更适合指示何时满足条件(配置完成)的工作。但是使用 condvar 需要上述所有条件,再加上一个 condvar,并且需要处理虚假唤醒的可能性,据我所知,这对于互斥锁来说不是问题。

有没有更好的方法来产生一个线程,然后让它立即停止,这样我就可以在允许它进一步运行之前使用它的本机句柄来配置它?

【问题讨论】:

  • 在生成的线程 (functionToRun()) 中进行等待而不是在生成线程中进行等待不是更有意义吗?即,是否让刚刚生成的线程进入睡眠状态,直到生成器发出“配置完成,继续”的信号?
  • @DevSolar:这就是代码应该做的。生成线程获取互斥体,因此生成的线程在尝试获取它时会阻塞。当生成线程解锁互斥锁(表明配置完成)时,生成的线程可以继续。请注意,生成的函数不是 functionToRun,它是调用 functionToRun 的 lambda 生成的闭包。

标签: c++ multithreading c++11


【解决方案1】:

当我希望延迟一个线程的 main 函数的启动,直到一些外部配置完成时,我使用 future。这避免了自旋等待,并具有与互斥锁或 condvar 相同的阻塞属性,但提供了更清晰的意图。使用此模式,您可以将示例编写为:

std::promise<void> p;
std::thread t([&p]{
    p.get_future().wait();
    thread_func();
}

auto nh=t.native_handle();
// configure nh
p.set_value();

我特别喜欢将此模式与 shared_future 一起用于多线程测试 --- 这样您可以确保所有线程都在运行并准备好在测试开始之前进行。

【讨论】:

    猜你喜欢
    • 2011-06-20
    • 2011-08-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-06
    • 2020-05-05
    相关资源
    最近更新 更多