Take the 2-minute tour ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

The purpose of this is to prevent a re-entrant function call in a single thread, e.g. prevent the situation where func() calls bar() which calls func().

This is currently not used in any multithreaded code (and does not plan to be).

struct TranLock
{
static int count;
    bool failed;
    TranLock() { failed = count; if (!failed) ++count; }
    ~TranLock() { if (!failed) --count; }
};
int TranLock::count = 0;

Usage:

void func()
{
    TranLock lock;
    if ( lock.failed )
        return;   // or take other action

    // the function's logic here
}

Is there a better idiom for this, e.g. involving std::shared_ptr ? C++11 features OK.

Update: As pointed out by Greg Hewgill, if multiple functions use TranLock they will all have a shared lockout. Currently I only use it in one function, although it would be nice to see two different possible implementations:

  • Lock which can be shared amongst functions
  • Individual lock per function

(perhaps this could be controlled with a template parameter or something).

share|improve this question
    
Why not just a static variable inside the function? –  Thomas Padron-McCarthy Jun 16 at 6:56
    
That's really messy , RAII is essential –  Matt McNabb Jun 16 at 7:17

2 Answers 2

The obvious problem with this is it will detect any function that uses TranLock calling any other function that also uses TranLock (since there is only a single global count). That is, if func() (which uses TranLock) calls bar() (which also uses TranLock) then bar() will erroneously fail.

In order to make a lock like this that can be used with multiple functions, create a class with no static members, then in each function where you want to use a lock, create a static instance of the class. That way, each function will have its own independent counter. However, you can't rely on the class destructor in this case because the destructor of static objects is not called when the object goes out of scope.

You could use a hybrid of these two techniques, for example

struct TranLock
{
    int &count;
    TranLock(int &count): count(count) { failed = count; if (!failed) ++count; }
    ~TranLock() { if (!failed) --count; }
};

void func()
{
    static int TranLock_count;
    TranLock lock(TranLock_count);
    if (lock.failed) {
        ...
    }
    ...
}

Finally, you don't really need to maintain an int count at all. Since you only ever increment count when it is zero, a bool flag would do equally well.

share|improve this answer

How about: - or just use a mutex.aquire() instead of the bool and you're threadsafe.

class lock
{
    bool &b_;

public:
    lock( bool &b )
      : b_( b )
    {
        if( b ) throw reentry_exception;
        b = true;
    }
    ~lock()
    {
        b = false;
    }
};

static bool func_running = false;
void func()
{
    lock mylock = lock( func_running );
}
share|improve this answer
    
Sorry - my mistake! The lock object should of course be initialized on the stack, without new! –  Falco Jun 16 at 10:57
    
A mutex is not appropriate because the OP asked for a way to prevent a re-entrant function call in a single thread. –  Greg Hewgill Jun 18 at 20:37
    
@GregHewgill That depends on the mutex-implementation used, there are some mutexes which will allow any number of acquires by the same thread and some mutexes which will only allow one acquire by any thread - so they will work the same for single and multi-threaded! –  Falco Jun 19 at 0:15
    
Yes, that's true, but neither of those options will do what the original question asked for - one kind of mutex will ignore recursive calls on the same thread and the other kind will deadlock. –  Greg Hewgill Jun 19 at 0:17

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.