如果尚未持有,则获取 read/write 锁
Acquire a read/write lock if not already held
在GLib中,是否有一个操作告诉它“如果你还没有持有锁,就获取它”?同一个线程能否两次获取锁(使第二次获取成为空操作,或要求它被释放两次)或测试它是否已经持有特定的锁?
假设我的代码中有以下函数:
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);
}
假设:
shared_data
指向共享数据结构,线程间访问需要同步
shared_data->rw_lock
是同步访问的read/write锁
func_a()
和func_b()
都可以从外部调用
mess_with_data()
和 mess_with_data_again()
不是线程安全的,因此调用者在调用它们之前需要对数据持有写锁
- 它们不仅仅是单个函数调用,而是语句行,因此将
func_b()
的主体复制到 func_a()
不是一个选项(代码重复,可维护性差)
func_a()
和 func_b()
的调用者无法直接访问锁,因此需要在后台进行锁定
- 将
func_b()
的函数体(没有 locking/unlocking)提取到由 func_a()
和 func_()
调用的单独的辅助函数中不是一个选项(它们是分布在多个模块中,并且在函数调用之间存在抽象层——实际上,func_a()
并不直接按名称调用 func_b()
,而是一个恰好解析为 func_b()
的指针)。
我该如何解决这个问题?
首先要注意的是:您要查找的词是“recursive”。
虽然 GMutex
明确提到互斥锁是否递归是未定义的,但 AFAIK GRWLock
只是省略了任何关于 writer 锁是否是递归的提及递归(reader 端是递归的)。
如果您深入研究一下实现,您会发现 POSIX GRWLock
是使用 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.").所以基本上不,GRWLock
不是递归的写锁。
至于如何解决你的问题,我的第一个建议是让 mess_with_data
和 mess_with_data_again
自己获取和释放锁。请记住,您只应在必要时持有锁,而不要再持有锁。
如果出于某种原因这不是一个选项(比如您可能无法访问该代码),您可以使用递归锁,或者将写入器操作限制在一个线程中并使用队列与它。
也可以重构 mess_with_data
和 mess_with_data_again
,使它们不需要锁,但这可能会也可能不会,而且可能会非常困难。
在GLib中,是否有一个操作告诉它“如果你还没有持有锁,就获取它”?同一个线程能否两次获取锁(使第二次获取成为空操作,或要求它被释放两次)或测试它是否已经持有特定的锁?
假设我的代码中有以下函数:
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);
}
假设:
shared_data
指向共享数据结构,线程间访问需要同步shared_data->rw_lock
是同步访问的read/write锁func_a()
和func_b()
都可以从外部调用mess_with_data()
和mess_with_data_again()
不是线程安全的,因此调用者在调用它们之前需要对数据持有写锁- 它们不仅仅是单个函数调用,而是语句行,因此将
func_b()
的主体复制到func_a()
不是一个选项(代码重复,可维护性差) func_a()
和func_b()
的调用者无法直接访问锁,因此需要在后台进行锁定- 将
func_b()
的函数体(没有 locking/unlocking)提取到由func_a()
和func_()
调用的单独的辅助函数中不是一个选项(它们是分布在多个模块中,并且在函数调用之间存在抽象层——实际上,func_a()
并不直接按名称调用func_b()
,而是一个恰好解析为func_b()
的指针)。
我该如何解决这个问题?
首先要注意的是:您要查找的词是“recursive”。
虽然 GMutex
明确提到互斥锁是否递归是未定义的,但 AFAIK GRWLock
只是省略了任何关于 writer 锁是否是递归的提及递归(reader 端是递归的)。
如果您深入研究一下实现,您会发现 POSIX GRWLock
是使用 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.").所以基本上不,GRWLock
不是递归的写锁。
至于如何解决你的问题,我的第一个建议是让 mess_with_data
和 mess_with_data_again
自己获取和释放锁。请记住,您只应在必要时持有锁,而不要再持有锁。
如果出于某种原因这不是一个选项(比如您可能无法访问该代码),您可以使用递归锁,或者将写入器操作限制在一个线程中并使用队列与它。
也可以重构 mess_with_data
和 mess_with_data_again
,使它们不需要锁,但这可能会也可能不会,而且可能会非常困难。