我怎样才能使共同对象的访问线程安全?

时间:2018-04-03 23:12:24

标签: c++ multithreading synchronization race-condition critical-section

我搜索了整个SO论坛,但找不到任何合理的答案。我知道通过使用互斥和信号量等同步机制可以使资源共享成为线程安全,但我的问题是不同的。假设您有Logger logger个对象。通过引用传递给所有正在运行的线程。此logger对象具有Logger::log函数,其中资源(日志文件)由多个线程访问。我可以使用该方法用互斥体包装这个关键部分,以防止竞争条件。但是,如何防止多个线程访问共享Logger logger对象时可能发生的竞争条件。我可以传递一个常见的互斥锁和Logger logger对象,并尝试在使用之前获取该对象,但该解决方案并不优雅。什么是在这种情况下防止竞争状况的最佳方法?

1 个答案:

答案 0 :(得分:1)

Single Responsibility Principle更加同步,而not to pay for what you dont use的C ++理念是让Logger类仅负责日志记录。想象一下,你想重新使用它来记录单线程应用程序 - 那么为什么要支付额外的同步资源呢。

但当然对于多线程应用程序 - 您将需要线程之间的同步机制。实现这一目标的一个好方法是使用Decorator Design Pattern - 如下所示:

class ILogger 
{
public: 
   virtual ~ILogger() = default;

   // as many log methods as you need
   virtual void log(args) = 0;
};

然后让您的Logger从ILogger派生并实施。

然后定义添加同步的装饰器:

class SynchronizedLogger : public ILogger 
{
public: 
   SynchronizedLogger (ILogger& logger) : logger(logger) {} 

   // as many log methods as you need
   void log(args) override
   {
       std::lock_guard<std::mutex> lock(logGuard);
       logger.log(args);
   }

private:
   std::mutex logGuard;
   ILogger& logger; 
};

您只需确保所有将使用日志记录的线程在构建SynchronizedLogger后开始并在销毁之前停止:

int main() {
   Logger logger{...}; 
   SynchronizedLogger syncLogger{logger};

   std::thread t1([&syncLogger] { syncLogger.log("T1"); });
   std::thread t2([&syncLogger] { syncLogger.log("T2"); });
   std::thread t3([&syncLogger] { syncLogger.log("T3"); });
   std::thread t4([&syncLogger] { syncLogger.log("T4"); });

  t1.join();
  t2.join();
  t3.join();
  t4.join();
}