C++11并发; condition_variable; fizz, buzz, fizzbuzz; STUCK

问题描述 投票:0回答:1

我找不到任何bug,程序不显示任何输出;但是如果我在number()中引入一个cout,并在之后的while中引入一些print,我就会看到一些输出,是不是信号被遗漏了?

我已经启动了4个线程,所有线程都在一个共同的mutex和一个条件变量上使用unique_lock。如果我使用semaphores的话,同样的逻辑也可以工作,但是当我把它们转换为c++11 condition_variable时,我在屏幕上没有看到任何输出。线程被挂起,正在等待信号。但是线程[3]应该运行,因为它所在的条件wait if true; curr=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个回答
1
投票

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

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

#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;
}

© www.soinside.com 2019 - 2024. All rights reserved.