如何在使用wxCRIT_SECT_LOCKER时防止死锁

how to prevent deadlock when using wxCRIT_SECT_LOCKER

本文关键字:LOCKER 死锁 SECT wxCRIT      更新时间:2023-10-16

我正在用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()时,我们将进入关键部分两次,一次在Recorder::warning()[/em>中,另一次在*Logger:∶do_log()*中。

如果你同意这个问题是真实的,并且可能导致死锁,我如何避免多个锁(使用wxCriticalSection类/宏)。

通常要做的是创建不接受锁的内部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时,互斥锁被解锁。