Question

I'm writing a singleton Logger class in c++. this class provides logging API to multiple threads. to make it thread safe I'm using wxCRIT_SECT_LOCKER macro.

say I have this in my Logger class the following functions (simple example):

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;
}

Problem:

when Logger::warning() is called we'll enter the critical section twice, once in Logger::warning() and one more time in *Logger::do_log()*.

If you agree the problem is real and can cause deadlock, how can I avoid multiple locks (using wxCriticalSection class/macros).

Was it helpful?

Solution

What is often done is to create internal APIs that do not take locks that are called by the public APIs that do take the locks.

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;
}

However, for your problem, you may rather use wxMutex directly, and use the type wxMUTEX_RECURSIVE when you construct it. This way, a mutex has count. When the mutex is first locked, the count is set to 1. If the same thread grabs the mutex again, it increments a count. Releasing the mutex decrements the count. When the count reaches 0, the mutex is unlocked.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top