I don't want the function to be entered simultaneously by multiple threads, neither do I want it to be entered again when it has not returned yet. Is there any approach to achieve my goal? Thank you very much!
views:
285answers:
7Generally you need to introduce a monitor, e.g. in Java by adding the "synchronized" keyword to your method signature.
(Am I right?)
Blocking the function from being entered by other threads while it's in progress on one thread is pretty straightforward as explained by the other answers. But if you want it to block in the same thread when it's already been entered... well, that's a deadlock.
You can do something like this:
int some_shared_var = 0;
...
for (;some_shared_var != rank;) ;
run_my_function();
some_shared_var++;
rank is your thread number (assumig you have threads with numbers 0 to size-1).
This is only example. Real implementation will be different. It depends on what library/functions you want to use to parallelize your code (fork, MPI etc). But I hope it gives you some useful thoughts.
Since you're saying C++ and Windows, have a look at critical sections. You'll likely want to to wrap it in a couple of C++ classes, though, for ease of use.
Critical sections try spinlooping for a short duration, if the lock is already taken. For short pieces of code, this can often avoid doing a full blocking wait, and thus the overhead of user<>kernel mode etc.
Use a critical section (InitializeCriticalSection(), EnterCriticalSection(), LeaveCriticalSection() ) and also implement an entry counter. The critical section will guard against reentry from different threads and the entry counter will guard against reentry from the same thread.
To implement an entry counter use a common variable (boolean for your case) and a bracket class. Once you've already entered the critical section (and therefore no other thread will execute the same code in parallel) check the value of the variable. If it states that the function has been entered already - leave (first release the critical section, then leave the function). Otherwise construct your bracket class instance that will change the variable value. So the next time this thread enters the function it will check the variable, see that reentry has happened and leave. The destructor of the bracket class will change the variable to its original value once you leave the function.
It's wise to use bracket classes for both the critical section entry and for the entry counter changing so that your code is exception safe and all actions are performed in necessary order and regardless of how yoou leave the function - on exception or on return statement.
f will only be called runs only, when nobody else is currently running it. (This is concept demonstration with only Win32 calls)
void f();
err call_f()
{
static HMUTEX hMutex;
if( !hMutex )
{
hMutex = ::CreateMutex( 0, TRUE, 0 );
}
else
{
if( WaitForSingleObject( hMutex, 0 ) != WAIT_OBJECT_0 )
return ERR_ALREADY_RUNNING;
}
// calling f here
f();
ReleaseMutex( hMutex );
return S_OK;
}
Beware the minimal checking, the missing cleanup code for the mutex and the race-condition on first enter.