我正在用c ++编写单例Logger类。此类为多个线程提供日志记录API。使其线程安全我正在使用 wxCRIT_SECT_LOCKER 宏。
说我在我的Logger类中有以下函数(简单示例):
void Logger::error( string msg )
{
wxCRIT_SECT_LOCKER(adapter_locker, gs_LogBufferShield);
// do something such as getting/setting class members
m_err_cnt++;
do_log("Error: " + msg);
}
void Logger::warning( string msg )
{
wxCRIT_SECT_LOCKER(adapter_locker, gs_LogBufferShield);
// do something such as getting/setting class members
m_warn_cnt++;
do_log("Warning: " + msg);
}
void Logger::do_log( string msg )
{
wxCRIT_SECT_LOCKER(adapter_locker, gs_LogBufferShield);
// do something such as getting/setting class members
m_log_cnt++;
cout << msg << endl;
}
问题:
当 Logger :: warning()被调用时,我们将进入两次关键部分,一次进入 Logger :: warning(),再进入一次* Logger :: do_log()*。
如果您同意问题是真实的并且可能导致死锁,那么如何避免多次锁定(使用wxCriticalSection类/宏)。
答案 0 :(得分:1)
通常做的是创建内部API,这些API不接受由执行锁定的公共API调用的锁。
void Logger::error( string msg )
{
wxCRIT_SECT_LOCKER(adapter_locker, gs_LogBufferShield);
m_err_cnt++;
do_log_internal("Error: " + msg);
}
void Logger::warning( string msg )
{
wxCRIT_SECT_LOCKER(adapter_locker, gs_LogBufferShield);
m_warn_cnt++;
do_log_internal("Warning: " + msg);
}
void Logger::do_log( string msg )
{
wxCRIT_SECT_LOCKER(adapter_locker, gs_LogBufferShield);
do_log_internal(msg);
}
void Logger::do_log_internal( string msg )
{
m_log_cnt++;
cout << msg << endl;
}
但是,对于您的问题,您可能更直接使用wxMutex
,并在构造时使用类型wxMUTEX_RECURSIVE
。这样,互斥量就算了。首次锁定互斥锁时,计数设置为1.如果同一线程再次抓取互斥锁,则会增加计数。释放互斥锁会减少计数。当计数达到0时,互斥锁将被解锁。