Clean Critical Sections

Another thing that I find irksome is:

pthread_mutex_lock (&my_mutex);
    // critical section code
pthread_mutex_unlock (&my_mutex);

Instead, I'd much rather code:

mutex_lock (&my_mutex) {
    // critical section code
}

Why? I find the curly brackets a much better delineator of the critical section. (Yes, this can be done much more cleanly in C++)

Well, good news. This can be done in C, fairly easily!

#define mutex_lock(__s) \
    for (int __control=!!pthread_mutex_lock (__s) + 1;\
         __control;\
         pthread_mutex_unlock (__s), __control = 0)

To understand how this works, let's do the macro expansion of the previous example:

for (int __control = !!pthread_mutex_lock (&my_mutex)) + 1;
     __control;
     pthread_mutex_unlock (&my_mutex), __control = 0) {
    // critical section code
}

And unroll the for loop into the equivalent while loop:

int __control = !!pthread_mutex_lock (&my_mutex) + 1;
while (__control) {
    // critical section code
    pthread_mutex_unlock (&my_mutex);
    __control = 0;
}

So, this does the pthread_mutex_lock, and sets control to a nonzero value ("!!" is the boolean typecast operator, rendering its victims to be a zero or a one — add 1 to that and it's always nonzero. Long story).

The while loop enters the body with the mutex locked, executes the critical section, and then unlocks the mutex and resets control to zero. (Yeah, it uses the comma operator inside of the for loop, but I've shown a semicolon for greater clarity in the unroll. Same shit, different pile.)

Hacks

It was pointed out that if someone accidentally cut-n-pasted some code into the critical section that had a break statement, it would prevent this from working. No problemo!

#define mutex_lock(__s) for (int __control=!!pthread_mutex_lock (__s) + 1;\
                             __control;\
                             pthread_mutex_unlock (__s), __control = 0)\
                                 for (int __control = 1; __control; __control = 0) 

Nice eh? The break would only break out of the second for loop, which is really a "who cares?" situation.

This does bring out the point that:

    for (int __control = 1; __control; __control = 0) 

Is a nice macro way to generate a control section for a C statement.