C++11 线程卡在锁定互斥锁上

标签 c++ multithreading c++11 locking mutex

使用 C++11 std::threadstd::mutex,我正在编写一个简单的工作线程。 但是,我在锁定 std::mutex 时遇到了一个奇怪的挂起问题,看起来两个线程(主线程和工作线程)都试图锁定互斥锁,但都被阻止了。

完整代码

#include <thread>
#include <condition_variable>
#include <memory>
#include <iostream>
#include <list>
std::condition_variable cv;
std::mutex m;
std::thread t;
bool shouldExit = false;
std::list<int> jobs;

void thread_func()
{
  std::unique_lock<std::mutex> lock(m);
  while (!shouldExit) {
    while (jobs.empty() && !shouldExit) {
      cv.wait(lock);
    }
    // Do some stuff
    if (jobs.empty()) {
      continue;
    }
    // Get a job and do something with it
    if (!lock.owns_lock()) {
      lock.lock();  // <<<< Worker thread hang here
    }
    auto j = std::move(jobs.front());
    jobs.pop_front();
    lock.unlock();
    std::cout << "Do something with job " << j << std::endl;
    std::this_thread::sleep_for(std::chrono::milliseconds(1));
  }
}

int main()
{
  t = std::thread(thread_func);

  for (int i = 1; i < 100; ++i) {
    std::cout << "Push to job " << i << std::endl;
    {
    std::lock_guard<std::mutex> lock(m); // <<<< main thread hang here
    jobs.push_back(i);
    cv.notify_one();
    }
    std::this_thread::sleep_for(std::chrono::milliseconds(1));
  }

  // To wait for thread exit
  shouldExit = true;
  cv.notify_one();
  t.join();
  return 0;
}

我正在 Ubuntu 14.04 上使用以下命令编译代码

g++ -std=c++11 -g -O0 -pthread -o testthread testthread.cpp

执行结果一般是这样的:

$ ./testthread
Push to job 1
Do something with job 1
Push to job 2
Do something with job 2
Push to job 3
Push to job 4

有趣的是,当我将主线程中的一行 sleeping-1ms 代码移动到 lock_guard 中时,问题就消失了。

  for (int i = 1; i < 100; ++i) {
    std::cout << "Push to job " << i << std::endl;
    {
    std::lock_guard<std::mutex> lock(m);
    jobs.push_back(i);
    cv.notify_one();
    std::this_thread::sleep_for(std::chrono::milliseconds(1)); // Moved into lock_guard
    }
  }

我想不通为什么。 你能帮忙解释一下代码的行为以及我做错了什么吗?

[更新] 我知道以某种方式重写工作线程可以解决这个问题。但是我仍然想知道在原始代码中当两个线程锁定互斥锁但都被阻塞时到底发生了什么。

最佳答案

lock 未锁定的情况下调用 cv.wait 是未定义的行为。添加此断言:

while (!shouldExit) {
  assert(lock.owns_lock());    // <------ add this
  while (jobs.empty() && !shouldExit) {
    cv.wait(lock);
  }

libc++ 将从 wait if !lock.owns_lock() 中抛出,但我不知道其他实现会做什么。

关于C++11 线程卡在锁定互斥锁上,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36602080/

相关文章:

java - 同步 vs ReentrantLock vs AtomicInteger 执行时间

c++ - 如何使一个类可分配给基元?或者,如何制作标量类?

c++ - 多维 vector 字符串

C++ 共享库 : Creation and usage

c# - 根据 C# 中的条件保护临界区

java - 在多处理器系统中,每个处理器都会有独立的JVM吗?

c++ - 为什么 std::less 是一个仿函数?

C++:为什么引入 std::vector::data 成员函数?

c++ - 如何确定地址是否缓存对齐?

c++ - 在 std::thread 中等待条件 A 或条件 B