4

我正在尝试创建一个日志记录类,其中写入日志的调用是静态的。现在,由于性能要求,我想在单独的线程中执行实际的日志记录。由于写入日志的函数是静态的,我认为线程也需要是静态的,这也与另一个执行实际写入日志的静态成员函数相关联。我尝试对其进行编码,但不知何故它在静态线程的初始化过程中挂起。复制该行为的代码示例如下:

“记录器.h”

#ifndef LOGGER_H
#define LOGGER_H

#include <condition_variable>
#include <mutex>
#include <queue>
#include <string>
#include <thread>
#include <vector>

#define LIBRARY_EXPORTS

#ifdef LIBRARY_EXPORTS // inside DLL
#define LIBRARY_API __declspec(dllexport) 
#else // outside DLL
#define LIBRARY_API __declspec(dllimport)
#endif 

using namespace std;

namespace Company { namespace Logging {

class LIBRARY_API Logger
{
public:
    ~Logger();

    void static Write(string message, vector<string> categories = vector<string>());

private:
    Logger();
    Logger(Logger const&) {}
    void operator=(Logger const&) {}

    static thread processLogEntriesThread;

    static void ProcessLogEntries();
};

}}

#endif

“记录器.cpp”

#include "Logger.h"

#include <iostream>

using namespace std;

namespace Company { namespace Logging {

thread Logger::processLogEntriesThread = thread(&Logger::ProcessLogEntries);

Logger::Logger()
{
}

Logger::~Logger()
{
    Logger::processLogEntriesThread.join();
}

void Logger::Write(string message, vector<string> categories)
{
    cout << message << endl;
}

void Logger::ProcessLogEntries()
{
}

}}

我发现的一个奇怪行为是,仅当类打包在 DLL 中时才会发生挂起部分。如果我将类文件直接使用到控制台 EXE 项目中,它似乎可以工作。

所以基本上我的问题是悬挂部分,如果我做对了。

提前致谢...

4

3 回答 3

1

挂起部分仅在类打包在 DLL 中时发生

有关挂起原因的完整详细信息,请参阅动态链接库最佳实践:

您不应该从内部执行以下任务DllMain

  • 打电话CreateThread。如果你不与其他线程同步,创建一个线程可以工作,但它是有风险的。

解决方案是为您的记录器库提供一个用户必须显式调用的初始化函数/对象main,而不是在main输入之前初始化一个全局线程对象。这个函数应该创建线程。

或者在第一次记录调用时使用std::call_once. 但是,这涉及对每个日志调用进行额外的条件检查。这张支票可能很便宜,但不是免费的。

于 2019-01-31T10:55:00.343 回答
1

您可以使用我的记录器库 => https://github.com/PraGitHub/Prapository/tree/master/C_Cpp/Logger

如果发现这篇文章无关紧要,请原谅我。

于 2019-01-31T10:46:16.410 回答
0

我看不到记录器线程的任何用法。将线程作为类中的成员并不意味着所有成员函数都将在创建的线程中运行。当您没有记录器实例时,记录器的析构函数将永远不会被调用。iostream 不是线程安全的!

你必须做的:

创建某种存储来收集日志信息。这个实例必须是线程安全的!将来自外界的消息推送到此实例中。实例本身必须有一个自己的线程,该线程从存储中读取数据并将数据放到输出中。这也必须以线程安全的方式完成,因为读取和写入来自不同的线程!

于 2013-09-14T09:45:18.850 回答