Search code examples
c++multithreadingboostboost-thread

Call method right after blocking call


I'm using a third party library which has a blocking function, that is, it won't return until it's done; I can set a timeout for that call.

Problem is, that function puts the library in a certain state. As soon as it enters that state, I need to do something from my own code. My first solution was to do that in a separate thread:

void LibraryWrapper::DoTheMagic(){
    //...
    boost::thread EnteredFooStateNotifier( &LibraryWrapper::EnterFooState, this );
    ::LibraryBlockingFunction( timeout_ );
    //...
}

void LibraryWrapper::EnterFooState(){
   ::Sleep( 50 ); //Ensure ::LibraryBlockingFunction is called first
   //Do the stuff
}

Quite nasty, isn't it? I had to put the Sleep call because ::LibraryBlockingFunction must definitely be called before the stuff I do below, or everything will fail. But waiting 50 milliseconds is quite a poor guarantee, and I can't wait more because this particular task needs to be done as fast as possible.

Isn't there a better way to do this? Consider that I don't have access to the Library's code. Boost solutions are welcome.

UPDATE: Like one of the answers says, the library API is ill-defined. I sent an e-mail to the developers explaining the problem and suggesting a solution (i.e. making the call non-blocking and sending an event to a registered callback notifying the state change). In the meantime, I set a timeout high enough to ensure stuff X is done, and set a delay high enough before doing the post-call work to ensure the library function was called. It's not deterministic, but works most of the time.


Solution

  • Would using boost future clarify this code? To use an example from the boost future documentation:

    int calculate_the_answer_to_life_the_universe_and_everything()
    {
        return 42;
    }
    
    boost::packaged_task<int> pt(calculate_the_answer_to_life_the_universe_and_everything);
    boost::unique_future<int> fi=pt.get_future();
    
    boost::thread task(boost::move(pt));
    
    // In your example, now would be the time to do the post-call work.
    
    fi.wait(); // wait for it to finish
    

    Although you will still presumably need a bit of a delay in order to ensure that your function call has happened (this bit of your problem seems rather ill-defined - is there any way you can establish deterministically when it is safe to execute the post-call state change?).