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