【问题标题】:How to make two threads take turns executing their respective critical sections after one thread ends一个线程结束后如何让两个线程轮流执行各自的临界区
【发布时间】:2020-07-26 17:04:11
【问题描述】:

在带有 STL 线程的现代 C++ 中,我希望有两个工作线程轮流工作。一次只能有一个人工作,每个人只能在另一个人转身之前转一圈。我有这部分工作。 增加的约束是一个线程需要在另一个线程完成后继续轮流。但是在我的代码中,剩余的工作线程在第一个工作线程完成后会死锁。我不明白为什么,因为第一个工人做的最后一件事是解锁并通知条件变量,这应该唤醒第二个。代码如下:

{
    std::mutex mu;
    std::condition_variable cv;
    int turn = 0;

    auto thread_func = [&](int tid, int iters) {
        std::unique_lock<std::mutex> lk(mu);
        lk.unlock();

        for (int i = 0; i < iters; i++) {
            lk.lock();
            cv.wait(lk, [&] {return turn == tid; });

            printf("tid=%d turn=%d i=%d/%d\n", tid, turn, i, iters);
            fflush(stdout);

            turn = !turn;
            lk.unlock();
            cv.notify_all();
        }
    };

    auto th0 = std::thread(thread_func, 0, 20);
    auto th1 = std::thread(thread_func, 1, 25); // Does more iterations

    printf("Made the threads.\n");
    fflush(stdout);

    th0.join();
    th1.join();

    printf("Both joined.\n");
    fflush(stdout);
}

我不知道这是否是我不了解 STL 线程中的并发性,还是我的代码中存在逻辑错误。请注意,SO 上有一个与此类似的问题,但第二个工人不必比第一个工人运行更长的时间。我现在找不到链接到它。提前感谢您的帮助。

【问题讨论】:

  • 当两个线程使用同一个互斥锁进行同步时,唯一的保证是只有一个线程会同时锁定互斥锁。不能保证当线程 A 释放时,线程 B 会成功锁定。如果你想要这样的序列,那么你需要自己实现它。这意味着两个线程必须合作以跟踪哪个线程最后拥有锁,并且每个线程必须检查哪个线程最后拥有锁,如果另一个线程仍在运行并且没有最近的锁,则立即释放。跨度>
  • 谢谢。不过,我想知道,如果不能保证线程可以成功锁定,那么在任何使用互斥锁的代码中如何确保向前进展?有人可以使用互斥锁编写单线程代码,并且在获取互斥锁时可能会死锁。另外,如果不唤醒线程并导致它们开始执行,notify_all 是什么意思?
  • 在线程(代码中的)设计、它们如何共享数据以及它们如何同步时需要解决这个问题。当一个线程释放一个互斥锁时,另一个尝试抓取(或随后尝试抓取)该互斥锁的线程很有可能会成功。但是不能保证哪个线程首先成功。实际上,如果您的代码依赖于特定的顺序,最好将相关的代码部分放在一个线程中,并按顺序执行它们(例如,执行 A 然后 B 并重复的循环)。
  • 那种锁步执行意味着你真的没有使用线程。
  • 也许这意味着我没有没有使用线程,但你可以清楚地看到我正在使用线程。我在这里建模的情况实际上是由于其他原因存在两个工作线程,它们在代码的不同部分执行不同的操作。然后有一段时间他们聚在一起,必须做这个锁步工作。在锁定步骤期间,我同意更明显的实现是先做 A 然后 B,然后重复。但这不适用于两个线程的更广泛的上下文。

标签: c++ multithreading stl


【解决方案1】:

当一个线程完成后,另一个将等待没有人发送的通知。当只剩下一个线程时,您需要停止使用条件变量或以其他方式向条件变量发出信号。

【讨论】:

  • 嗯.... 为什么说它在等待没有人发送的通知?它使用 cv.notify_all() 发送它。在所有其他迭代中,这成功地唤醒了另一个线程。为什么这次不这样做?
  • 第二个线程将它发送给第一个,现在第二个线程消失了。
猜你喜欢
  • 2015-02-24
  • 2022-11-16
  • 2021-12-23
  • 1970-01-01
  • 2022-01-05
  • 2015-02-22
  • 2016-07-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多