【问题标题】:Equivalent of WAIT_ABANDONED in C++11 threading等价于 C++11 线程中的 WAIT_ABANDONED
【发布时间】:2013-06-03 21:18:28
【问题描述】:

我正在重写使用 WinAPI 进行线程处理的代码,以使用新的标准线程库。

我想知道在 C++11 中用什么等效的方式来发现互斥体被遗弃或丢失。

以下代码必须将初始化过程“外包”给创建的线程,但在完成并知道初始化结果之前不应返回。

bool Foo::Example()
{
    m_thread = std::thread(&Foo::ThreadProc, this);

    // wait for event before waiting for mutex
    WaitForSingleObject(m_hEvent, INFINITE);
    ResetEvent(m_hEvent);

    // the thread aquired the mutex. now wait until it is released or abandoned
    DWORD ret = WaitForSingleObject(m_hMutex, INFINITE);
    ReleaseMutex(m_hMutex);

    // check the result
    if (ret == WAIT_ABANDONED)
        return false;
    return true;
}
void Foo::ThreadProc()
{
    // aquire mutex and signal that it's done
    WaitForSingleObject(m_hMutex, INFINITE);
    SetEvent(m_hEvent);

    // ... initialization (required to be in this thread)

    if (initializationfailure)
        return; // failure. mutex is abandoned

    // success. mutex is unlocked
    ReleaseMutex(m_hMutex);

    // ... do the work
}

WAIT_ABANDONED 检查的替代品是什么?我在 std::mutex 中没有找到任何东西。它甚至说The behavior is undefined if the mutex is not unlocked before being destroyed, i.e. some thread still owns it. 没有等价物吗? std 线程库中的任何内容都接近这个?

我还接受改进代码的建议。对于这么简单的任务,似乎同步太多了。

【问题讨论】:

  • 标准中没有等效项(从您引用的措辞中应该很清楚)。也就是说,您不能便携地执行此操作。一个特定的实现可能会以某种方式提供对这个特性的支持,但是生成的程序将处于“未定义的行为”状态,一旦你在那里,一切都会发生。
  • 故意使用 WAIT_ABANDONED 是一个严重的错误,应始终保留它以指示代码中的严重线程错误。如果你使用微软的 std::mutex 实现,那么你会得到完全不同的东西,它不使用操作系统互斥锁。它建立在 ConcRT 库之上。它从头开始重新实现同步原语。当 std::mutex 对象被删除并且仍然持有锁时,您将得到一个断言。仅在调试版本中,在发布版本中静默失败。

标签: c++ multithreading winapi c++11


【解决方案1】:

没有等价物。您可以使用 RAII 解锁互斥锁并避免一开始就放弃它,然后您就不需要对其进行测试。

您可以使用 future 而不是等待事件并使用互斥锁,这比容易出错的显式同步简单得多:

bool Foo::Example()
{
    std::promise<bool> p;
    auto res = p.get_future();
    m_thread = std::thread(&Foo::ThreadProc, this, std::ref(p));
    return res.get();
}
void Foo::ThreadProc(std::promise<bool>& p)
{
    // ... initialization (required to be in this thread)

    if (initializationfailure)
    {
        p.set_value(false); // failure.
        return;
    }

    p.set_value(true);

    // IMPORTANT: p is a dangling reference now!

    // ... do the work
}

主线程会阻塞直到promise被实现,然后根据初始化是否成功返回true或false。

您可以通过将其设置为ThreadProc(std::promise&lt;bool&gt; p) 来避免悬空引用,然后将其作为std::move(p) 而不是std::ref(p) 传递,但我认为Visual C++ 中的std::thread 不支持仅移动类型的完美转发。

【讨论】:

  • 谢谢。这并不能真正解决问题。我需要等待初始化,但同时表示成功或失败。
  • @typ1232,我添加了一个比依赖废弃互斥锁更简单的替代方法
  • @typ1232:如果您需要指示成功或失败,只需为此使用一个额外的变量。您应该使用放弃与未放弃来传达程序状态。 WAIT_ABANDONED 状态是“哦,废话,发生了可怕的事情,可怕 错误,最好现在尽快退出”标志,而不是在正常程序操作期间应该发生的事情。
猜你喜欢
  • 2014-06-18
  • 1970-01-01
  • 1970-01-01
  • 2014-11-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-09
相关资源
最近更新 更多