Nicolas
Nicolas

Reputation: 13

deadlock c++ thread condition variable

I have a problem with a class called Workers.

Workers::Workers(int _nbThreads):
  goWork(false),
  progressWork(false),
  endWork(false),
  endFinishedWork(false),
  nbThreads(_nbThreads)
{

  for(int i=0;i<nbThreads;i++){ 
    threads.push_back(new std::thread(&Workers::threadsExecute,this,i));
  }
}

void Workers::threadsExecute(int numThread){
  for(;;){
    std::unique_lock<std::mutex> uniqueMutexWork(mutexWork);
    conditionWorkStarted.wait(uniqueMutexWork, [this] {return goWork==true;});
    progressWork=true;
    mutexWork.unlock();
    conditionWorkProgress.notify_all();
    for(;!endWork;);
    mutexWork.lock();
    endFinishedWork=true;
    mutexWork.unlock();
    conditionWorkFinished.notify_all();
    break;

  }
}

void Workers::threadsEnd(){
  for(int i=0;i<nbThreads;i++){ 
    threads[i]->join();
  }
}



void Workers::startWork(int numThread){
  std::unique_lock<std::mutex> uniqueMutexWork(mutexWork);
  goWork=true;
  conditionWorkStarted.notify_all();
  conditionWorkProgress.wait(uniqueMutexWork, [this] {return progressWork==true;});  
}

void Workers::stopWork(int numThread){
  std::unique_lock<std::mutex> uniqueMutexWork(mutexWork);
  endWork=true;
  conditionWorkFinished.wait(uniqueMutexWork, [this] {return endFinishedWork==true;});   
}

The main :

Workers workers* = new Workers(1);//Only one thread worker
workers->startWork(0);
workers->stopWork(0);

The problem is that the variable endWork is never found to true in

for(;!endWork;);  

However, this one is well put to true in the stopWork method :

endWork=true;

If I replace

  for(;!endWork;); 

by

for(;!endWork;){printf("work\n");}

The program works well ! What is my error ?

I look forward to your response.

Upvotes: 1

Views: 67

Answers (1)

Andriy Berestovskyy
Andriy Berestovskyy

Reputation: 8534

for(;!endWork;){printf("work\n");} The program works well ! What is my error ?

Since the variable endWork is a regular variable, compiler with high optimization option (i.e. -O3) might assume the variable does not change and optimize out the read inside the loop, i.e. it transforms the loop:

for( ; !endWork; ) ;

to

if(!endWork) for (;;) ;

With printf() there are too many things going on, so the compiler cannot figure out if we change endWork variable inside the printf(). So, it does not optimize the loop as shown above.

How to deal with the issue? The simplest would be to declare endWork as volatile. This will give compilation a hint, that the value endWork might be changed elsewhere (i.e. by another thread), so it will not optimize the loop as showed above.

Upvotes: 0

Related Questions