【问题标题】:C++11 concurrency; condition_variable; fizz, buzz, fizzbuzz; STUCKC++11 并发;条件变量;嘶嘶声,嗡嗡声,嘶嘶声;卡住
【发布时间】:2020-06-09 03:13:32
【问题描述】:

我找不到任何错误,程序没有显示任何输出;但是,如果我在看到一些输出之后在 number() 中引入一些 print 的 cout,是否会丢失信号?

我已经启动了 4 个线程,所有线程都在一个公共互斥锁和一个条件变量上使用了 unique_lock。如果我使用信号量,则相同的逻辑可以工作,但是当我将它们转换为 c++11 condition_variable 时,我在屏幕上看不到任何输出。线程挂起并等待信号。但是线程[3] 应该运行,因为它等待的条件为真;当前=1。

#include<iostream>
#include<thread>
#include<mutex>  
using namespace std; 

class FizzBuzz {
private:
    int n;
    int curr;
    std::mutex mtx; 
    std::condition_variable cv;

public:
    FizzBuzz(int n) {
        this->n = n;
        curr = 1;
    }

    // printFizz() outputs "fizz".
      void fizz(function<void()> printFizz) {
        while(curr <= n) {
            std::unique_lock<std::mutex> lck(mtx);
            cv.wait(lck, [&]{return (curr <= n && curr % 3 == 0 && curr % 5 != 0);});
            printFizz();
            curr++;
            lck.unlock();
            cv.notify_all();
        }
    }

    // printBuzz() outputs "buzz".
      void buzz(function<void()> printBuzz) {
        while(curr <= n) {
            std::unique_lock<std::mutex> lck(mtx);
            cv.wait(lck, [&]{return (curr <= n && curr % 3 != 0 && curr % 5 == 0);});
            printBuzz();
            curr++;
            lck.unlock();
            cv.notify_all();
        }
    }

    // printFizzBuzz() outputs "fizzbuzz".
      void fizzbuzz(function<void()> printFizzBuzz) {
        while(curr <= n) {
            std::unique_lock<std::mutex> lck(mtx);
            cv.wait(lck, [&]{return (curr <= n && curr % 3 == 0 && curr % 5 == 0);});
            printFizzBuzz();
            curr++;
            lck.unlock();
            cv.notify_all();
        }
    }

    // printNumber(x) outputs "x", where x is an integer.
      void number(function<void(int)> printNumber) {
        while(curr <= n) {
            std::unique_lock<std::mutex> lck(mtx);
            cv.wait(lck, [&]{return (curr <= n && curr % 3 != 0 && curr % 5 != 0);});
            printNumber(curr);
            curr++;
            lck.unlock();
            cv.notify_all();
        }
    }
};
void printFizz (void) {
  cout << "Fizz";
};
void printBuzz (void) {
  cout << "Buzz";
};
void printFizzBuzz (void) {
  cout << "FizzBuzz";
};
void printNumber (int n) {
  cout << n;
};

int main(int argc, char* argv[]) {
  int num;

  sscanf(argv[1], "%d", &num);

  std::function<void(void)> f_fizz     = printFizz;
  std::function<void(void)> f_buzz     = printBuzz;
  std::function<void(void)> f_fizzbuzz = printFizzBuzz;
  std::function<void(int)>  f_num      = printNumber;
  FizzBuzz *objPtr = new FizzBuzz(num);

  std::thread threads[4];


  threads[0] = std::thread(&FizzBuzz::fizz, objPtr ,f_fizz);
  threads[1] = std::thread(&FizzBuzz::buzz,objPtr, f_buzz);
  threads[2] = std::thread(&FizzBuzz::fizzbuzz,objPtr, f_fizzbuzz);
  threads[3] = std::thread(&FizzBuzz::number,objPtr, f_num);

  for (auto& th: threads) th.join();
  return 0;
}

【问题讨论】:

    标签: multithreading c++11 concurrency condition-variable fizzbuzz


    【解决方案1】:

    notify_all 到达其他线程,但条件curr &lt;=n &amp;&amp; ... 不满足。因此,其他线程继续等待并挂起程序。

    例如,以下代码将正确终止,因为设置终止标志将唤醒所有线程并让它们中断循环。

    #include<iostream>
    #include<thread>
    #include<mutex>  
    #include <functional>
    #include <condition_variable>
    using namespace std; 
    
    class FizzBuzz {
    private:
        int n;
        int curr;
        std::mutex mtx; 
        std::condition_variable cv;
        bool terminated;
    
    public:
        FizzBuzz(int n) {
            this->n = n;
            curr = 1;
            terminated = false;
        }
    
        // printFizz() outputs "fizz".
          void fizz(function<void()> printFizz) {
            while(curr <= n) {
                std::unique_lock<std::mutex> lck(mtx);
                cv.wait(lck, [&]{return (terminated || (curr % 3 == 0 && curr % 5 != 0));});
                if (terminated)
                    break;
                printFizz();
                curr++;
                lck.unlock();
                cv.notify_all();
            }
            cout << "fizz exiting" << endl;
            terminated = true;
        }
    
        // printBuzz() outputs "buzz".
          void buzz(function<void()> printBuzz) {
            while(curr <= n) {
                std::unique_lock<std::mutex> lck(mtx);
                cv.wait(lck, [&]{return (terminated || (curr % 3 != 0 && curr % 5 == 0));});
                if (terminated)
                    break;
                printBuzz();
                curr++;
                lck.unlock();
                cv.notify_all();
            }
            cout << "buzz exiting" << endl;
            terminated = true;
        }
    
        // printFizzBuzz() outputs "fizzbuzz".
          void fizzbuzz(function<void()> printFizzBuzz) {
            while(curr <= n) {
                std::unique_lock<std::mutex> lck(mtx);
                cv.wait(lck, [&]{return (terminated || (curr % 3 == 0 && curr % 5 == 0));});
                if (terminated)
                    break;
                printFizzBuzz();
                curr++;
                lck.unlock();
                cv.notify_all();
            }
            cout << "fizzbuzz exiting" << endl;
            terminated = true;
        }
    
        // printNumber(x) outputs "x", where x is an integer.
          void number(function<void(int)> printNumber) {
            while(curr <= n) {
                std::unique_lock<std::mutex> lck(mtx);
                cv.wait(lck, [&]{return (terminated || (curr % 3 != 0 && curr % 5 != 0));});
                if (terminated)
                    break;
                printNumber(curr);
                curr++;
                lck.unlock();
                cv.notify_all();
            }
            cout << "number exiting" << endl;
            terminated = true;
        }
    };
    void printFizz (void) {
      cout << "Fizz" << endl;
    };
    void printBuzz (void) {
      cout << "Buzz" << endl;
    };
    void printFizzBuzz (void) {
      cout << "FizzBuzz" << endl;
    };
    void printNumber (int n) {
      cout << n << endl;
    };
    
    int main(int argc, char* argv[]) {
      int num;
    
      sscanf(argv[1], "%d", &num);
    
      std::function<void(void)> f_fizz     = printFizz;
      std::function<void(void)> f_buzz     = printBuzz;
      std::function<void(void)> f_fizzbuzz = printFizzBuzz;
      std::function<void(int)>  f_num      = printNumber;
      FizzBuzz *objPtr = new FizzBuzz(num);
    
      std::thread threads[4];
    
    
      threads[0] = std::thread(&FizzBuzz::fizz, objPtr ,f_fizz);
      threads[1] = std::thread(&FizzBuzz::buzz,objPtr, f_buzz);
      threads[2] = std::thread(&FizzBuzz::fizzbuzz,objPtr, f_fizzbuzz);
      threads[3] = std::thread(&FizzBuzz::number,objPtr, f_num);
    
      for (auto& th: threads) {
          th.join();
      }
      return 0;
    }
    
    

    【讨论】:

    • 感谢您的快速回复。我无法理解为什么在 cv.notify_all() 条件“curr
    • @abhins 在您的实现中,最后一个打印线程将递增currnotify_all。因此所有其他线程将评估curr &lt;= nfalse 并继续等待。如果您对答案感到满意,请将其标记为已接受。
    • 谢谢。在把它放到 gdb 之后,我现在意识到了这一点。 curr 的值为 21,但线程仍在等待。他们没有条件出来..这样修改..cv.wait(lck, [&]{return (curr > n || (curr % 3 == 0 && curr % 5 != 0)); }); if (curr > n) 中断;
    • 这引出了另一个问题。如果 curr 确实达到了 21,为什么 cout 没有显示迄今为止打印的数字的输出?可以做些什么来刷新输出?感谢您的帮助!
    • @abhins 你没有使用cout &lt;&lt; "string" &lt;&lt; endl。因此, cout 将缓冲输出,直到它看到下一行字符。另一种选择是使用flush 而不是\n
    猜你喜欢
    • 2011-04-26
    • 2011-02-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多