Многопоточный не может присоединиться правильно - PullRequest
3 голосов
/ 06 марта 2019
#include <iostream>
#include <vector>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <atomic>
using namespace std;
mutex m;
condition_variable cov;
bool ready = false;
bool processed = false;
void showNum(int &f_, atomic_bool &alive_)
{
    while(alive_)
    {
        unique_lock<mutex> lk(m);
        cov.wait(lk,[]{ return ready;});
        f_++;
        ready = false;
        processed= true;
        lk.unlock();
        cout<<f_<<endl;
        cov.notify_one();
    }

}
int main() {
    vector<int> va;
    for (int i = 0; i < 10; ++i) {
        va.push_back(i);
    }
    int f = 0;
    atomic_bool alive{ true };


    std::thread t1(showNum,ref(f),ref(alive));
    auto sizeofVector = va.size();
    for (int j = 0; j < sizeofVector; ++j) {
        {
            lock_guard<mutex> lk0(m);
            f = va.back();
            cout<<f<<"    ";
            ready = true;
        }

        cov.notify_one();
        va.pop_back();
        {
            unique_lock<mutex> lk(m);
            cov.wait(lk,[]{return processed;});
            processed = false;
            lk.unlock();
        }

    }

    alive = false;
    t1.join();
    return 0;
}

Я просто хочу проверить условную переменную в многопоточности. Код выше - мой тестовый код.

ошибка в том, что поток t1 не может присоединиться правильно. Я печатаю alive_, это всегда правда, не может быть установлено в false на alive = false в главном потоке.

Я пытаюсь сделать alive глобальной переменной, но все равно та же ошибка.

Можете ли вы дать мне совет?

Ответы [ 3 ]

2 голосов
/ 06 марта 2019

Может быть изменено

cov.wait(lk,[]{ return ready;});

на

cov.wait(lk,[&alive_]{ return ready || !alive_;});
if (!alive_)
    break;

И ниже alive_=false; добавить строку

cov.notify_one();

Полный код выглядит следующим образом

#include <iostream>
#include <vector>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <atomic>
using namespace std;
mutex m;
condition_variable cov;
bool ready = false;
bool processed = false;
void showNum(int &f_, atomic_bool &alive_)
{
    while(alive_)
    {
        unique_lock<mutex> lk(m);
        cov.wait(lk,[&alive_]{return ready || !alive_;});
        if (!alive_)
            break;
        f_++;
        ready = false;
        processed= true;
        lk.unlock();
        cout<<f_<<endl;
        cov.notify_one();
    }

}
int main() {
    vector<int> va;
    for (int i = 0; i < 10; ++i) {
        va.push_back(i);
    }
    int f = 0;
    atomic_bool alive{ true };


    std::thread t1(showNum,ref(f),ref(alive));
    auto sizeofVector = va.size();
    for (int j = 0; j < sizeofVector; ++j) {
        {
            lock_guard<mutex> lk0(m);
            f = va.back();
            cout<<f<<"    ";
            ready = true;
        }

        cov.notify_one();
        va.pop_back();
        {
            unique_lock<mutex> lk(m);
            cov.wait(lk,[]{return processed;});
            processed = false;
            lk.unlock();
        }

    }

    alive = false;
    cov.notify_one();

    t1.join();
    return 0;
}
1 голос
/ 06 марта 2019

В t1 функция не проверяет постоянно alive. Вы разработали его так, чтобы каждый цикл начинался с ожидания переменной условия. Затем он идет спать и просыпаться только при получении уведомления. К сожалению, когда main устанавливает значение false в false, поток t1 все еще находится в состоянии ожидания.

Вы можете наблюдать это легко:

void showNum(int &f_, atomic_bool &alive_)
{
    while(alive_)
    {   cout<<"waiting..."<<endl;   
        unique_lock<mutex> lk(m);
        cout<<"waiting more..."<<endl;
        cov.wait(lk,[]{ return ready;});  ///<<<<< stuck here 
        cout<<"go..."<<endl;
        f_++;
        ready = false;
        processed= true;
        lk.unlock();
        cout<<"  sn:"<<f_<<endl;
        cov.notify_one();
    }
}

Он проснется только в том случае, если main обеспечит еще одно уведомление о условной переменной. Только в этот момент он выйдет из состояния ожидания и после обработки обнаружит, что alive равно false.

Чтобы не застрять навсегда, вы можете изменить свой код и использовать wait_for(), чтобы функция могла проверить время ожидания, если оно все еще остается alive.

0 голосов
/ 07 марта 2019
#include <iostream>
#include <vector>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <atomic>
#include <chrono>
using namespace std;
mutex m;
condition_variable cov;
bool ready = false;
bool processed = false;
atomic_bool alive{ true };
void showNum(int &f_, atomic_bool &alive_)
{
    while(alive)
    {
        unique_lock<mutex> lk(m);
        cov.wait(lk,[]{ return ready || !alive;});
        if(!alive)
            break;
        f_++;
        ready = false;
        processed= true;
        lk.unlock();
        cout<<f_<<endl;
        cov.notify_one();
    }

}
int main() {
    vector<int> va;
    for (int i = 0; i < 10; ++i) {
        va.push_back(i);
    }
    int f = 0;



    std::thread t1(showNum,ref(f),ref(alive));
    auto sizeofVector = va.size();
    for (int j = 0; j < sizeofVector; ++j) {
        {
            lock_guard<mutex> lk0(m);
            f = va.back();
            cout<<f<<"    ";
            ready = true;
        }

        cov.notify_one();
        va.pop_back();
        {
            unique_lock<mutex> lk(m);
            cov.wait(lk,[]{return processed;});
            processed = false;
            lk.unlock();
        }

    }
    alive = false;
    cov.notify_one();
    t1.join();
    return 0;
}

Интегрируя совет, я изменяю свой код, чтобы он был выше.Это вывод, как я ожидал.Спасибо всем, кто дал совет, с наилучшими пожеланиями.

...