将线程安全性添加到简单的日志记录功能?

Jon*_*hop 3 c++ windows multithreading iostream thread-safety

从我读到的,标准输出流通常不是线程安全的.我有一个C++应用程序(基于Windows,使用Visual Studio 2005)具有非常简单的日志记录功能:

void logText(string text)
{
    if(g_OutputLogEnabled && g_OutputLog.is_open())
    {
        string logDate = getDateStamp("%Y-%m-%d %H:%M:%S");
        g_OutputLog << "[" << logDate << "]: " << text << endl;
    }

    cout << text << endl; // Also echo on stdout
}
Run Code Online (Sandbox Code Playgroud)

在这个例子中,g_OutputLog是一个ofstream并且g_OutputLogEnabled是一个布尔值.

我一直在我的主应用程序中使用这个小函数没有问题,但我现在想将其用途扩展到一些子线程.这些线程在工作完成后可以工作并异步打印数据.

问题:如何在此例程中添加简单的行级线程安全性?所有我真正关心的是,我的日志中的每一行都保持不变.在这种情况下,性能不是问题,但(一如既往)更快更好.

我知道我可以使用第三方日志包,但我想自己做,所以我可以学习它是如何工作的.我的多线程知识不应该是它应该是什么,我正在努力改进它.

我听过关键部分一词,我有点意识到互斥锁和信号量,但在这种情况下我会使用哪些?有一个干净,简单的解决方案吗?提前感谢任何建议.

Naw*_*waz 6

使用范围锁定,例如:

void logText(string text)
{
    if(g_OutputLogEnabled && g_OutputLog.is_open())
    {
        string logDate = getDateStamp("%Y-%m-%d %H:%M:%S");

        boost::scoped_lock (g_log_mutex);  //lock
        g_OutputLog << "[" << logDate << "]: " << text << endl;

    } //mutex is released automatically here

    boost::scoped_lock (g_cout_log_mutex); //lock on different mutex!
    cout << text << endl; // Also echo on stdout
}
Run Code Online (Sandbox Code Playgroud)

或者你可以使用,std::unique_lock如果你的编译器支持这个.


scoped_lock如果你不能使用Boost,如果你没有,你将如何实施std::unique_lock

首先定义mutex类:

#include <Windows.h>

class mutex : private CRITICAL_SECTION  //inherit privately!
{
public:
     mutex() 
     {
        ::InitializeCriticalSection(this);
     }
     ~mutex() 
     {
        ::DeleteCriticalSection(this);
     }
private:

     friend class scoped_lock;  //make scoped_lock a friend of mutex

     //disable copy-semantic 
     mutex(mutex const &);           //do not define it!
     void operator=(mutex const &);  //do not define it!

     void lock() 
     {
        ::EnterCriticalSection(this);
     }
     void unlock() 
     {
        ::LeaveCriticalSection(this);
     }
};
Run Code Online (Sandbox Code Playgroud)

然后定义scoped_lock为:

class scoped_lock
{
      mutex & m_mutex;
  public:
      scoped_lock(mutex & m) : m_mutex(m) 
      {
          m_mutex.lock();
      }
      ~scoped_lock()
      {
          m_mutex.unlock();
      }
};
Run Code Online (Sandbox Code Playgroud)

现在你可以使用它们了.