CppCoreGuidelines CP.22 保有一个锁的时候不要调用未知代码
26 June 2023
“Never call unknown code while holding a lock (e.g., a callback)”
理由
如果你不知道某段代码做什么,你就可能遇到死锁。
void do_this(Foo* p) { lock_guard<mutex> lck {my_mutex}; // ... do something ... p->act(my_data); // ... }
如果你不知道 Foo::act
是做什么的,可能是一个虚函数,调用派生类的成员,而该派生类可能目前还没开发出来。也可能使递归调用 do_this
函数,导致
my_mutex
死锁。可能会因为某个其他互斥锁而锁住了,不能在某个合理的时间内返回。也就会导致任何调用这个函数的其他地方产生延时。
例子
常见的有“调用未知代码”问题的例子是,调用一个函数,而这个函数尝试对同一个对象进行锁定使用。这类问题通常可以使用 recursive_mutex
解决。
例子
recursive_mutex my_mutex; template<typename Action> void do_something(Action f) { unique_lock<recursive_mutex> lck {my_mutex}; // ... do something ... f(this); // f will do something to *this // ... }
如果 f()
在 *this
进行操作,我们必须在调用前,保证对象的不变式。
强化
- 标记保有非递归互斥锁的时候,调用虚函数的情况。
- 标记保有非递归互斥锁的时候,调用回调函数的情况。