我有一个类,其中一个成员函数调用另一个成员功能两次。它调用的函数为了线程安全而锁定互斥对象。调用的工作方式是,为了使调用函数是线程安全的,我需要确保两个函数调用都是在没有另一个线程执行InnerFunction
的情况下完成的。
基本上,我需要外部函数锁定内部函数使用的相同互斥锁,以确保在外部函数完成之前不会执行对该内部函数的其他调用。
示例:
int InnerFunction()
{
const std::lock_guard<std::mutex> lock(m_mutex);
// Do stuff
}
int OuterFunction()
{
// Lock the mutex to ensure thread safety
const std::lock_guard<std::mutex> lock(m_mutex);
// Call the inner function twice while the mutex is locked
// both calls need to complete before we can free the mutex or we can end up with a race condition
InnerFunction();
InnerFunction();
} // mutex unlocked here
问题是,如果他们锁定了同一个互斥锁,那么当内部函数获取锁时,它将无法获得,因为它已经被外部函数锁定了。处理这种情况的最佳方法是什么?
简单地从InnerFunction
中移除锁是不起作用的,因为InnerFunction
可以自己调用,并且它需要锁定互斥锁,以确保它不会与来自不同线程的对同一函数的另一个调用存在竞争条件。
这只是一个设计问题。
- 公共函数应该锁定互斥对象
- Private函数应该需要一个锁定的互斥锁作为先决条件
- 不要在内部调用公共函数
如果InnerFunction
既可以在外部调用,也可以在内部调用,那么它应该被拆分为一个锁定互斥锁的公共互斥锁和一个实际执行工作的私有(未锁定(互斥锁。
class A {
public:
int InnerFunction() {
std::lock_guard<std::mutex> lock(m_mutex);
unlockedInnerFunction();
}
int OuterFunction() {
std::lock_guard<std::mutex> lock(m_mutex);
unlockedInnerFunction();
unlockedInnerFunction();
}
private:
// The functions below require a locked mutex
int unlockedInnerFunction() {
// Do stuff
}
std::mutex m_mutex;
};
请注意,这不是std::recursive_mutex
的作用。
std::recursive_mutex
是一种破解方法,适用于无法控制整个调用链的情况,例如调用用户提供的回调,这些回调可能会反过来回调到您的代码、可抢占的ISR等。
在这里应用std::recursive_mutex
将是低效的,而且有代码气味。