Упрощенная цель состоит в том, чтобы принудительно вызывать 3 функции-члена в 3 разных потоках один за другим (поток A вызывает F :: first, поток BF :: second, поток CF :: third).
InЧтобы получить порядок выполнения потоков, я использовал 1 условную переменную и 2 bools, указывающие, закончили ли первый и второй потоки свою работу.
В коде:
std::mutex mtx;
std::condition_variable cv;
bool firstPrinted = false;
bool secondPrinted = false;
class F {
public:
void first(std::function<void()> printFirst) {
std::unique_lock<std::mutex> lck(mtx);
std::cout << "first\n";
printFirst();
firstPrinted = true;
cv.notify_one();
}
void second(std::function<void()> printSecond) {
std::unique_lock<std::mutex> lck(mtx);
std::cout << "second\n";
cv.wait(lck, []() { return firstPrinted; });
printSecond();
secondPrinted = true;
cv.notify_one();
}
void third(std::function<void()> printThird) {
std::unique_lock<std::mutex> lck(mtx);
std::cout << "third\n";
cv.wait(lck, []() { return secondPrinted; });
printThird();
}
};
auto first = []() {
std::cout << "1";
};
auto second = []() {
std::cout << "2";
};
auto third = []() {
std::cout << "3";
};
F f;
std::thread A(&F::first, &f, first);
std::thread B(&F::second, &f, second);
std::thread C(&F::third, &f, third);
A.join(); B.join(); C.join();
Теперь давайте рассмотримэта ситуация:
Поток A не запускается первым - независимо от того, был ли первый начальный поток B или C, они оба блокируют (ждут), пока не получат уведомление (B блокирует до получения уведомления от A, и C блокирует до получения уведомления от B)
Бесконечное ожидание (или, возможно, тупик!?) Появляется, когда первым начальным потоком является C, что всегда приводит к следующему выводу:
third
second
first
...and stalling here
Теоретически это не должно происходить, потому что вызов cv.ожидание в потоке C разблокирует мьютекс, который позволяет запускать поток B, который, в свою очередь, также ожидает (потому что условие не стало истинным), и поэтому он разблокирует заблокированный мьютекс как wчто позволяет сначала запустить поток A, который, наконец, должен войти в критическую секцию и уведомить B.
Какой путь вызова вызывает остановку программы?
Какой нюанс я упустил?
Пожалуйста, поправьте меня, если я ошибся в приведенных выше мыслях.