Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Manually releasing boost locks?

For the sake of learning combinatorics of boost::thread I'm implementing a simple barrier (BR) for threads which lock a common mutex (M). However, as far as I get it when going to BR.wait() the locks on the mutex are not released, so in order for all threads to arrive at BR a manual release of the lock on M needs to be performed. So I have the following code:

boost::barrier BR(3);
boost::mutex M;

void THfoo(int m){
    cout<<"TH"<<m<<" started and attempts locking M\n";
    boost::lock_guard<boost::mutex> ownlock(M);

    cout<<"TH"<<m<<" locked mutex\n";
    Wait_(15); //simple wait for few milliseconds

    M.unlock(); //probably bad idea
    //boost::lock_guard<boost::mutex> ~ownlock(M);
    // this TH needs to unlock the mutex before going to barrier BR

    cout<<"TH"<<m<<" unlocked mutex\n";
    cout<<"TH"<<m<<" going to BR\n";
    BR.wait();
    cout<<"TH"<<m<<" let loose from BR\n";
}

int main()  
{  
    boost::thread TH1(THfoo,1);
    boost::thread TH2(THfoo,2);
    boost::thread TH3(THfoo,3);

    TH2.join(); //but TH2 might end before TH1, and so destroy BR and M
    cout<<"exiting main TH \n";

    return 0;  
}

Whereas M.unlock() is clearly a bad solution (not using the lock); so how to (simply) release the lock? Also: how do I (properly) wait in main() for all threads to finish? (TH2.join() is bad, `cause TH2 may finish first...);

Please do not suggest go-arounds, e.g. with conditional variables, which I can also use, but it must be possible to do it straightforwardly without them.

like image 511
P Marecki Avatar asked Dec 06 '22 15:12

P Marecki


2 Answers

In addition to scoping the boost::lock_guard in a block, you can also use a boost::unique_lock which can be unlock()'ed explicitly:

boost::unique_lock<boost::mutex> ownlock(M);

cout<<"TH"<<m<<" locked mutex\n";
Wait_(15); //simple wait for few milliseconds

ownlock.unlock();

This is useful if you need to release the mutex before reacquiring it later.

As for the joining, simply call join() on all thread handles in turn.

like image 163
liwp Avatar answered Dec 21 '22 02:12

liwp


Something like:

void THfoo(int m){
  // use a scope here, this means that the lock_guard will be destroyed (and therefore mutex unlocked on exiting this scope
  {
    cout<<"TH"<<m<<" started and attempts locking M\n";
    boost::lock_guard<boost::mutex> ownlock(M);

    cout<<"TH"<<m<<" locked mutex\n";
    Wait_(15); //simple wait for few milliseconds

  }
  // This is outside of the lock
  cout<<"TH"<<m<<" unlocked mutex\n";
  cout<<"TH"<<m<<" going to BR\n";
  BR.wait();
  cout<<"TH"<<m<<" let loose from BR\n";
}

As for the waiting, simply call join on all the thread handles (if they've completed already, the function will return immediately)

TH1.join();
TH2.join();
TH3.join();
like image 20
Nim Avatar answered Dec 21 '22 02:12

Nim