使用wxCRIT_SECT_LOCKER时如何防止死锁

时间:2013-08-20 07:30:02

标签: c++ multithreading deadlock critical-section

我正在用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类/宏)。

1 个答案:

答案 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时,互斥锁将被解锁。