gpt4 book ai didi

c++ - 使以下记录器实现线程安全的更好方法?

转载 作者:搜寻专家 更新时间:2023-10-31 01:26:31 25 4
gpt4 key购买 nike

我想用类似cout 的接口(interface)编写一个基本的线程安全记录器。我想出了以下类(class)设计。这绝对不是最好的设计,因为如果使用不当,它可能会陷入死锁,如 int main() 所示。

#include <iostream>
#include <sstream> // for string streams
#include <mutex>
#include <memory>

typedef std::ostream&(*endl)(std::ostream&);

class BasicLogger {

public:
enum SEVERITY {
CRITICAL,
ERROR,
WARNING
};

explicit BasicLogger(SEVERITY _s): s(_s) {
streamMutex.lock();
logStream.reset(new std::ostringstream);
}

~BasicLogger() {
std::cout << logStream->str();
streamMutex.unlock();
}

std::ostringstream& operator<< (const endl eof) {
(*logStream) << eof;
return (*logStream);
}

template<typename T>
std::ostringstream& operator<< (const T& obj) {
(*logStream) << obj;
return (*logStream);
}

static std::unique_ptr<std::ostringstream> logStream;

BasicLogger(const BasicLogger&) = delete;
BasicLogger& operator=(const BasicLogger&) = delete;

private:
SEVERITY s; //TODO
static std::mutex streamMutex;

};

/*=======================================================*/
std::unique_ptr<std::ostringstream> BasicLogger::logStream;
std::mutex BasicLogger::streamMutex;
/*=======================================================*/

int main() {

int a = 9;
int b = 8;

// BasicLogger l(BasicLogger::ERROR); //Deadlock situation

BasicLogger(BasicLogger::ERROR) << "Linux" << " " << a << " " << b << std::endl;
BasicLogger(BasicLogger::ERROR) << "MyMachine";
BasicLogger(BasicLogger::ERROR) << std::endl;

}

最佳答案

您在构造函数中锁定了互斥锁,并在析构函数中将其解锁。因此,不可能同时创建多个 BasicLogger 实例。

BasicLogger l(BasicLogger::ERROR); 将调用构造函数,从而获得锁。在 l 超出范围之前不会调用析构函数,这意味着互斥量在 l 超出范围之前保持锁定。

如果您尝试构造另一个 BasicLocker,您的构造函数试图获取直到 l 被销毁才可用的锁会导致死锁。

当您创建临时 BasicLogger 实例时,BasicLogger(BasicLogger::ERROR) 会调用构造函数,使用该对象,然后立即销毁。因此,被锁定的互斥锁被解锁。


由于您正在为每个 BasicLogger 实例创建独立的 std::stringstream,因此您需要一个锁来保护对 std::stringstream 的访问,因此多个线程可以写入同一个记录器。因此,每个实例都应该拥有一个互斥体。

您还需要一个静态互斥锁来保护对 std::cout 的同时访问。正在打印日志时获取锁,立即释放。当然,这要求所有对 std::cout 的访问都通过 BasicLogger 进行。

class BasicLogger {
public:
BasicLogger() = default;
~BasicLogger() {
std::lock_guard<std::mutex> lLock(localMutex); /* the order of locking is important */
std::lock_guard<std::mutex> gLock(globalMutex);
std::cout << stream.str();
}

/* TODO: satisfying the rule of 5 */

template <class T>
BasicLogger& operator<< (const T& item) {
std::lock_guard<std::mutex> lLock(localMutex);
stream << item;
return *this;
}

private:
std::ostringstream stream;
std::mutex localMutex;
static std::mutex globalMutex;
};

关于c++ - 使以下记录器实现线程安全的更好方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55210628/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com