In GLib, is there an operation to tell it “acquire the lock if you don’t hold it already”? Can the same thread acquire a lock twice (making the second acquisition a no-op, or requiring it to be released twice) or test if it is already holding a particular lock?
Suppose I have the following functions in my code:
void func_a() {
//g_rw_lock_writer_lock(&shared_data->rw_lock);
mess_with_data(shared_data);
func_b();
//g_rw_lock_writer_unlock(&shared_data->rw_lock);
}
void func_b() {
//g_rw_lock_writer_lock(&shared_data->rw_lock);
mess_with_data_again(shared_data);
//g_rw_lock_writer_unlock(&shared_data->rw_lock);
}
Assume that:
shared_data
points to a shared data structure, and access needs to be synchronized between threadsshared_data->rw_lock
is the read/write lock to synchronize accessfunc_a()
and func_b()
can be called from outsidemess_with_data()
and mess_with_data_again()
are not thread-safe, thus the caller needs to hold a write lock on the data before calling themfunc_b()
into func_a()
is not an option (code duplication, poor maintainability)func_a()
and func_b()
have no direct access to the lock, therefore locking needs to happen under the hoodfunc_b()
(sans the locking/unlocking) into a separate helper function called by both func_a()
and func_()
is not an option (they are spread out across multiple modules and there are layers of abstraction between the function calls—in fact, func_a()
does not directly call func_b()
by name but a pointer which happens to resolve to func_b()
).How would I solve this?
First things first: the word you're looking for is "recursive".
While GMutex
explicitly mentions that whether or not the mutex is recursive is undefined, AFAIK GRWLock
just omits any mention for whether the writer lock is recursive (the reader side is recursive).
If you dive into the implementation a bit, you'll see that on POSIX GRWLock
is implemented using a pthread_rwlock_t
, which needn't be recursive ("Results are undefined if the calling thread holds the read-write lock (whether a read or write lock) at the time the call is made."). So basically no, GRWLock
isn't recursive for writer locks.
As for how to solve your problem, my first suggestion would be to have mess_with_data
and mess_with_data_again
acquire and release the lock themselves. Remember, you should only hold locks for as long as necessary and no longer.
If that's not an option for some reason (like maybe you don't have access to that code), you could use a lock that is recursive, or restrict writer operations to one thread and use a queue to communicate with it.
It may also be possible to refactor mess_with_data
and mess_with_data_again
so they don't require locks, but that may or may not be possible and would likely be quite difficult.