I've been looking at the GCC docs for defining macros and it looks like what I want isn't possible, but I figure if it is, someone here would know.
What I want to do is define this macro:
synchronized(x) {
do_thing();
}
Which expands to:
{
pthread_mutex_lock(&x);
do_thing();
pthread_mutex_unlock(&x);
}
In C++ I could just make a SynchronizedBlock
object that gets the lock in its constructor and unlocks in the destructor, but I have no idea how to do it in C.
I realize I could use a function pointer in the form synchronized(x, &myfunction);
, but my goal is to make some C code look as much like Java as possible. And yes, I know this is evil.
EDIT: Changed to nategoose's version
#define synchronized(lock) \
for (pthread_mutex_t * i_#lock = &lock; i_#lock; \
i_#lock = NULL, pthread_mutex_unlock(i_#lock)) \
for (pthread_mutex_lock(i_#lock); i_#lock; i_#lock = NULL)
And you can use it like this:
synchronized(x) {
do_thing(x);
}
Or even without braces
synchronized(x)
do_thing();
Here's a start, but you may need to tweak it:
#define synchronized(lock, func, args...) do { \
pthread_mutex_lock(&(lock)); \
func(##args); \
pthread_mutex_unlock(&(lock)); \
} while (0)
Use like this (unfortunately, not the Java-like syntax you wanted):
synchronized(x, do_thing, arg1, arg2);
Very interesting question!
I looked at the other answers and liked the one using for
. I have an improvement, if I may! GCC 4.3 introduces the COUNTER macro, which we can use to generate unique variable names.
#define CONCAT(X, Y) X##__##Y
#define CONCATWRAP(X, Y) CONCAT(X, Y)
#define UNIQUE_COUNTER(prefix) CONCATWRAP(prefix, __COUNTER__)
#define DO_MUTEX(m, counter) char counter; \
for (counter = 1, lock(m); counter == 1; --counter, unlock(m))
#define mutex(m) DO_MUTEX(m, UNIQUE_COUNTER(m))
Using those macros, this code...
mutex(my_mutex) {
foo();
}
... will expand to...
char my_mutex__0;
for (my_mutex__0 = 1, lock(my_mutex); my_mutex__0 == 1; --my_mutex__0, unlock(m)) {
foo();
}
With my_mutex__n starting in 0 and generating a new name each time its used! You can use the same technique to create monitor-like bodies of code, with a unique-but-unknown name for the mutex.
This was the best I came up with:
#define synchronized(x, things) \
do { \
pthread_mutex_t * _lp = &(x); \
pthread_mutex_lock(_lp); \
(things); \
pthread_mutex_unlock(_lp); \
} while (0)
...
synchronized(x,(
printf("hey buddy\n"),
a += b,
printf("bye buddy\n")
));
Note that you have to use the rarely used comma operator and there are restrictions to what code can live within the (not quite java-like) synchronization code list.