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:
What would be the most elegant way?
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.
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.
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
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With