Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to implement decorators in C and C++

Tags:

c++

c

decorator

I have a situation in C as well as in C++ which can be best solved with something like the Python like decorators: I have few a functions which I'd like to wrap around with something else so that before the function enters some statements are performs and when it leaves some other functionality is executed.

For instance, I have a few functions in a library C file which when called should lock a semaphore and before returning the control to callee, should release the semaphore. without the lock they have following structure:

int f1(int)
{
    ...
    ... 
}

int f2(char*)
{
    ....
}

int f3(blabla)
{
    ....
}

... fn(...)

I'd like to define a global semaphore which should be locked before each of these functions is called and released when the function is returned. I'd like to do it with as much simplicity as possible; something close to this:

#lockprotected
int f1(int)
{
   ... /* nothing changed over here */
}
#endlockprotected

or something like

int f1(int)
{
   ... /* nothing changed over here */
}
#lockprotected f1

What I don't want is:

  1. Change the function names as they are library functions and are being called from many places.
  2. Explicitly place any statement before return calls as most of the functions have many early returns in between. Or for that matter change any internals of the function.

What would be the most elegant way?

like image 344
sharjeel Avatar asked Jan 12 '11 09:01

sharjeel


3 Answers

Use RAII (resource acquisition is initialization) to define the lock on the mutex. This would allow you to forget about point #2, i.e., you don't need to keep track of return statement to release the lock.

class Lock {
public:
    Lock () { // acquire the semaphore }
    ~Lock () { // release the semaphore }
}

Next create objects of this class at the start of your functions, i.e.,

int f1 (int) {
    Lock l;
    // forget about release of this lock
    // as ~Lock() will take care of it
}

A side advantage of this is that even in the case of exceptions being thrown from f1(), you still don't need to worry about releasing the lock. All stack objects are destroyed before a function is exited.

like image 60
Jaywalker Avatar answered Oct 12 '22 23:10

Jaywalker


Define the wrapper like this:

class SemaphoreWrapper
{
private:
    semaphore &sem;
public
    SemaphoreWrapper(semaphore &s)
    {
        sem = s;
        sem.lock();
    }

    ~SemaphoreWrapper()
    {
        sem.unlock();
    }
}

Then simply create an instance of SemaphoreWrapper within each function:

void func1()
{
    SemaphoreWrapper(global_semaphore);


    ...
}

The constructor and destructor of SemaphoreWrapper will take care of the lock/unlock functionality.

like image 35
trojanfoe Avatar answered Oct 12 '22 23:10

trojanfoe


if you really want a C solution, you could go with macros like:

#define LOCK   lock( &yourglobalsemaphore )
#define UNLOCK unlock( &yourglobalsemaphore )

#define LOCKED_FUNCTION_ARG1(TRet, FuncName, TArg1, Arg1Name ) \
TRet FuncName( TArg1 Arg1Name ) { \
 LOCK; \
 TRet ret = FuncName##_Locked( Arg1Name ); \
 UNLOCK; \
 return ret \
} \
TRet FuncName##_Locked(TArg1 Arg1Name )

#define LOCKED_FUNCTION_ARG2(TRet FuncName, TArg1, Arg1Name, TArg2, Arg2Name) \
//...etc

but you will need 1 macro for every count of arguments (and the function should have a return type).

example usage:

LOCKED_FUNCTION_ARG1(int, f1, int, myintarg)
{
   //unchanged code here
}
like image 30
smerlin Avatar answered Oct 13 '22 00:10

smerlin