gpt4 book ai didi

multithreading - 同步3个线程以打印顺序输出

转载 作者:行者123 更新时间:2023-12-03 13:03:09 25 4
gpt4 key购买 nike

采访中有人问我这个问题。我真是一无所知。
因此,我决定学习一些多线程技术,并希望找到该问题的答案。

我需要使用3个线程来打印输出:01020304050607 ...

  • 线程1:打印0
  • Thread2:打印奇数
  • Thread3:打印偶数
  • #include <iostream>
    #include <thread>
    #include <mutex>
    #include <condition_variable>

    std::mutex m;
    std::condition_variable cv1, cv2, cv3;

    int count = 0;

    void printzero(int end)
    {
    while (count <= end)
    {
    std::unique_lock<std::mutex> lock(m);
    cv1.wait(lock);
    std::cout << 0 << " ";
    ++count;
    if (count % 2 == 1)
    {
    lock.unlock();
    cv2.notify_one();
    }
    else
    {
    lock.unlock();
    cv3.notify_one();
    }
    }
    }

    void printodd(int end)
    {
    while (count <= end)
    {
    std::unique_lock<std::mutex> lock(m);
    cv2.wait(lock);
    if (count % 2 == 1)
    {
    std::cout << count << " ";
    ++count;
    lock.unlock();
    cv1.notify_one();
    }
    }
    }

    void printeven(int end)
    {
    while (count <= end)
    {
    std::unique_lock<std::mutex> lock(m);
    cv3.wait(lock);
    if (count % 2 == 0)
    {
    std::cout << count << " ";
    ++count;
    lock.unlock();
    cv1.notify_one();
    }
    }
    }

    int main()
    {
    int end = 10;

    std::thread t3(printzero, end);
    std::thread t1(printodd, end);
    std::thread t2(printeven, end);

    cv1.notify_one();

    t1.join();
    t2.join();
    t3.join();

    return 0;
    }

    我的解决方案似乎处于僵局。我什至不确定逻辑是否正确。请帮忙

    最佳答案

    您的代码有几个问题。为了使它起作用,您需要执行以下操作:

  • 修改您的while (count <= end)检查。在不同步的情况下读取count是未定义行为(UB)。
  • std::condition_variable::wait 使用适当的谓词。没有谓词的代码问题:
  • 如果在notify_one之前调用wait,则通知将丢失。在最坏的情况下,对mainnotify_one调用是在线程开始运行之前执行的。结果,所有线程可能会无限期地等待。
  • Spurious wakeups可能会破坏您的程序流程。另请参见cppreference.com on std::condition variable
  • 使用std::flush(请确保)。

  • 我玩了很多您的代码。在下面,您找到了我应用建议的修复程序的版本。此外,我还尝试了一些其他想法。
    #include <cassert>

    #include <condition_variable>
    #include <functional>
    #include <iostream>
    #include <mutex>
    #include <thread>
    #include <vector>

    // see the `std::mutex` for an example how to avoid global variables

    std::condition_variable cv_zero{};
    std::condition_variable cv_nonzero{};

    bool done = false;
    int next_digit = 1;
    bool need_zero = true;

    void print_zero(std::mutex& mt) {
    while(true) {// do not read shared state without holding a lock
    std::unique_lock<std::mutex> lk(mt);
    auto pred = [&] { return done || need_zero; };
    cv_zero.wait(lk, pred);
    if(done) break;

    std::cout << 0 << "\t"
    << -1 << "\t"// prove that it works
    << std::this_thread::get_id() << "\n"// prove that it works
    << std::flush;

    need_zero = false;

    lk.unlock();
    cv_nonzero.notify_all();// Let the other threads decide which one
    // wants to proceed. This is probably less
    // efficient, but preferred for
    // simplicity.
    }
    }

    void print_nonzero(std::mutex& mt, int end, int n, int N) {
    // Example for `n` and `N`: Launch `N == 2` threads with this
    // function. Then the thread with `n == 1` prints all odd numbers, and
    // the one with `n == 0` prints all even numbers.
    assert(N >= 1 && "number of 'nonzero' threads must be positive");
    assert(n >= 0 && n < N && "rank of this nonzero thread must be valid");

    while(true) {// do not read shared state without holding a lock
    std::unique_lock<std::mutex> lk(mt);
    auto pred = [&] { return done || (!need_zero && next_digit % N == n); };
    cv_nonzero.wait(lk, pred);
    if(done) break;

    std::cout << next_digit << "\t"
    << n << "\t"// prove that it works
    << std::this_thread::get_id() << "\n"// prove that it works
    << std::flush;

    // Consider the edge case of `end == INT_MAX && next_digit == INT_MAX`.
    // -> You need to check *before* incrementing in order to avoid UB.

    assert(next_digit <= end);
    if(next_digit == end) {
    done = true;
    cv_zero.notify_all();
    cv_nonzero.notify_all();
    break;
    }

    ++next_digit;
    need_zero = true;

    lk.unlock();
    cv_zero.notify_one();
    }
    }

    int main() {
    int end = 10;
    int N = 2;// number of threads for `print_nonzero`

    std::mutex mt{};// example how to pass by reference (avoiding globals)

    std::thread t_zero(print_zero, std::ref(mt));

    // Create `N` `print_nonzero` threads with `n` in [0, `N`).
    std::vector<std::thread> ts_nonzero{};
    for(int n=0; n<N; ++n) {
    // Note that it is important to pass `n` by value.
    ts_nonzero.emplace_back(print_nonzero, std::ref(mt), end, n, N);
    }

    t_zero.join();
    for(auto&& t : ts_nonzero) {
    t.join();
    }
    }

    关于multithreading - 同步3个线程以打印顺序输出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56731861/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com