views:

285

answers:

7

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!

+7  A: 

Both goals can be achieved with a mutex semaphore.

happy_emi
By using this, you will merely _block_ the second entry within the same thread.
xtofl
But that is only possible in case of recursion. The problem can still be solved with a mutex. Just you have to lock it _before_ the function call (it this case a wrapper function could come in handy)
happy_emi
A: 

Generally you need to introduce a monitor, e.g. in Java by adding the "synchronized" keyword to your method signature.

(Am I right?)

chiccodoro
I'm not quite clear. I am using C++
Another thing that's not very clear: You don't want the function to be re-entered by the same thread when it has not returned yet? If the thread has not returned yet, it can consequently not be reentering the function?
chiccodoro
(I'm speaking of the "neither" part of your question)
chiccodoro
Why was this downvoted?
aib
+3  A: 

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.

Edmund
True about a deadlock. Usually it's done another way. The function checks if it has been already entered and if so returns. Good for some long-running event handlers invoked by a timer.
sharptooth
A: 

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.

klew
note that this one will also block (busy wait - polling) when re-entering from the same thread.
xtofl
+1  A: 

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.

snemarch
Critical sections won't guard against reentry by the same thread.
sharptooth
how would you re-enter a function from the same thread? The only way that could happen (that I can think of) would be recursion, which the critical section would stop - albeit deadlocking.
snemarch
It could be a handler for an event fired by a timer, for example. If it takes longer to execute the fucntion that the period between events reentry will occur.
sharptooth
Function A calls function B which calls function A, it can happen many ways if your function is designed crazily enough. Though of course you're right about the deadlock (is that the right term for this case?). Most applications would want the lock count to increase.
Dan Olson
@sharptooth: the timer events are going to be queued, not overriding the current execution path.@dan: agreed, as I understand OP didn't want re-entry though (achieving that without possible deadlock... ugh :))
snemarch
+3  A: 

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.

sharptooth
It sounds like your solution would *allow* re-entry from the same thread, and finally releasing the critsec when counter goes down to zero - is this what the OP wants? Also, you'd have to do the critsec *outside* the function for this to work.
snemarch
Yeap, first enter the section, then paly with the variable, check it's value and possible return from there.
sharptooth
+1  A: 

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.

Christopher