我怎样才能使公共共享对象的访问线程安全?
How could I make the access of commonly shared object thread-safe?
我搜索了整个 SO 论坛,但找不到任何合理的答案。我知道可以通过使用互斥锁和信号量等同步机制使资源共享成为线程安全的,但我的问题是不同的。假设您有一个 Logger logger
对象。它通过引用传递给所有 运行 线程。这个 logger
对象有一个 Logger::log
函数,其中一个资源(日志文件)被多个线程访问。我可以使用该方法用互斥量包装这个关键部分,以防止竞争条件。但是如何防止多个线程访问共享 Logger logger
对象时可能发生的竞争条件。我可以将一个公共互斥锁与 Logger logger
对象一起传递,并尝试在使用它之前获取该对象,但该解决方案并不优雅。在这个给定的场景中防止竞争条件的最好方法是什么?
与Single Responsibility Principle and C++ idea of not to pay for what you dont use更同步的是让Logger
class只负责日志记录。想象一下,您想重用它来登录单线程应用程序 - 那么为什么要支付额外的同步费用。
但当然对于 multi-threaded 应用程序 - 您将需要线程之间的同步机制。实现此目的的一种好方法是使用 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();
}
我搜索了整个 SO 论坛,但找不到任何合理的答案。我知道可以通过使用互斥锁和信号量等同步机制使资源共享成为线程安全的,但我的问题是不同的。假设您有一个 Logger logger
对象。它通过引用传递给所有 运行 线程。这个 logger
对象有一个 Logger::log
函数,其中一个资源(日志文件)被多个线程访问。我可以使用该方法用互斥量包装这个关键部分,以防止竞争条件。但是如何防止多个线程访问共享 Logger logger
对象时可能发生的竞争条件。我可以将一个公共互斥锁与 Logger logger
对象一起传递,并尝试在使用它之前获取该对象,但该解决方案并不优雅。在这个给定的场景中防止竞争条件的最好方法是什么?
与Single Responsibility Principle and C++ idea of not to pay for what you dont use更同步的是让Logger
class只负责日志记录。想象一下,您想重用它来登录单线程应用程序 - 那么为什么要支付额外的同步费用。
但当然对于 multi-threaded 应用程序 - 您将需要线程之间的同步机制。实现此目的的一种好方法是使用 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();
}