在 lambda 中通过引用捕获 thread_local 变量无法按预期工作

Mat*_*247 5 c++ lambda multithreading capture thread-local

我目前正在构建一个系统,其中有多个线程正在运行,一个线程可以将工作排队到另一个线程并等待完成。我使用互斥体和条件变量进行同步。为了避免为每个操作创建新的互斥体和 cv,我想对其进行优化,并尝试为每个正在等待的线程使用 thread_local 互斥体/cv 对。然而,这出乎意料地不起作用,我很有趣为什么。

基本上我的代码将工作排队到另一个线程并等待它,如下所示:

/* thread_local */ std::mutex mtx;
/* thread_local */ std::condition_variable cv;
bool done = false;  

io_service.post([&]() {
    // Execute the handler in context of the io thread
    functionWhichNeedsToBeCalledInOtherThread();

    // Signal completion to unblock the waiter
    {
        std::lock_guard<std::mutex> lock(mtx);
        done = true;
    }
    cv.notify_one();
});

// Wait until queued work has been executed in io thread
{
    std::unique_lock<std::mutex> lk(mtx);
    while (!done) cv.wait(lk);
}
Run Code Online (Sandbox Code Playgroud)

如果同步对象不是,则此方法可以正常工作thread_local。当我添加thread_local等待线程时,它会永远等待,这表明条件变量永远不会发出信号。我现在有一种感觉,尽管通过引用捕获对象,但另一个线程的 thread_local 对象在 lambda 内部使用。mtx我什至可以通过检查lambda 内部和外部的地址来确认捕获没有执行正确的操作-> 它们不匹配。

问题是:

  • 这是编译器中的错误还是设计使然?我正在使用 Visual Studio 2015,尚未检查其他编译器。
  • 是否允许通过引用捕获thread_local变量?

thread_local我可以通过创建对lambda 外部变量的显式引用并在其中使用这些引用来解决该错误。然而,我认为这种行为是出乎意料的,并且很想听到解释这是否是正确的行为。

yur*_*hek 3

您观察到的是正确的行为,因为您实际上没有捕获任何内容。静态和线程存储持续时间对象可以直接访问,因此为了提高效率[&]-capture 对这些对象没有影响。但是,您可以显式捕获适当的线程本地实例:

io_service.post([&mtx = mtx, &cv = cv]() {
Run Code Online (Sandbox Code Playgroud)