26 June 2023

C++ 核心指南目录

“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 进行操作,我们必须在调用前,保证对象的不变式。

强化

  • 标记保有非递归互斥锁的时候,调用虚函数的情况。
  • 标记保有非递归互斥锁的时候,调用回调函数的情况。