mercredi 28 mars 2018

Possible deadlock or concurrency related issues in C++11

I'm pretty new to C++ and I'm experimenting with some concurrency in C++ using threadpooling, condition variables, locks and mutex. The program is in essence a bunch threads of two categories sharing a common resource. Metaphorically, there are wolves and sheep, sharing a waterhole, and they can't be around the waterhole at the same time. Multiple sheeps or multiple wolves can however be there at the same time.

The threads are managed by a class called Waterhole, which holds a mutex, a condition variable and two integers which are supposed to keep track of how many wolves or sheep there are around the waterhole. There are also 4 methods which are for the entering/exiting of each animal. Here is my class:

    class Waterhole {

    private:
            int wolfInside;
            int sheepInside;
            mutex my_mutex;
            condition_variable CONVAR;
    public:
    void WolfEnters() {
        cout<<"A wolf enters the watercave\n"<<endl;
        unique_lock<mutex> lock(my_mutex);
        CONVAR.wait(lock, [this]{return sheepInside == 0;});
        wolfInside+=1;
    }
    void WolfLeaves() {

        cout<<"Wolf has finished drinking and is leaving the watercave\n";
        my_mutex.lock();
        wolfInside -= 1;
        CONVAR.notify_all();
    }
    void SheepEnters(){
        unique_lock<mutex> lock(my_mutex);
        cout<<"A Sheep enters the watercave\n";
        CONVAR.wait(lock, [this]{return wolfInside == 0;});
        sheepInside+=1;


    };
    void SheepLeaves() {

        cout<<"sheep has finished drinking and is leaving the watercave";
        my_mutex.lock();
        sheepInside-=1;
        CONVAR.notify_all();

    }




};

Here is the description of each thread, i.e wolves and sheeps:

    void sheep(Waterhole &waterhole) {

    int i = 0;
    while(i++ < SIM){

        this_thread::sleep_for(chrono::milliseconds(100));
        cout<<"Sheep is thirsty\n";
        waterhole.SheepEnters();
        this_thread::sleep_for(chrono::milliseconds(1));
        waterhole.SheepLeaves();
    }

}
void wolf(Waterhole &waterhole) {


    int i = 0;
    while(i++ < SIM){
        this_thread::sleep_for(chrono::milliseconds(100));
        cout<<"Wolf is thirsty\n";
        waterhole.WolfEnters();
        this_thread::sleep_for(chrono::milliseconds(1));
        waterhole.WolfLeaves();

    }
}

And finally here is my main method which creates and starts all threads:

int main() {

    vector<thread> threadvec;
    Waterhole waterhole;

    int nrSheep = 2;
    int nrWolf = 2;
    for (int i = 0; i < nrSheep; i++) {
        threadvec.push_back(move(thread(sheep, ref(waterhole))));
    }

    for (int i = 0; i < nrWolf; i++) {
        threadvec.push_back(move(thread(wolf,ref(waterhole))));
    }

    for (int i = 0; i < nrSheep; i++) {
        threadvec[i].join();
    }

    for (int i = 0; i < nrWolf; i++) {
        threadvec[i].join();
    }


    return 0;
}

Now to the problem at hand. Nor the Wolfs or the sheep ever leaves the waterhole. They are just able to enter!

Here is the output of the program:

 Sheep is thirsty
   Wolf is thirsty
   Wolf is thirsty
   Sheep  is thirsty
   A Sheep enters the watercave
   A Wolf enters the watercave
   A Wolf enters the watercave
   A Sheep enters the watercave

And after this the program never terminates, which is intended since I don't kill any threads in my program, but I believe that after the enter-methods, something with the locks and condition variables don't add upp.

I have googled this extensively and can't find anything similiar of what I'm trying to do. I believe that the output looks like this because of a deadlock.

Thanks in advance!

Aucun commentaire:

Enregistrer un commentaire