Search code examples
c++multithreadingboost-threadboost-mutex

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.


Solution

  • 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();