如何在C ++中对文件系统进行非并发打印?

时间:2014-08-08 14:00:34

标签: c++ io iostream ofstream

我正在用C ++编程,目的是在虚幻引擎4和我的服务器之间提供一些客户端/服务器通信。

我需要一个日志记录系统,但当前系统消息会泛滥。 所以我创建了一个带有ofstream对象的Logger类,我将其文件<< “写信息。” << ENDL。

问题是每个对象都会生成ofstream的另一个实例,并且对文件的几次更长时间的写入会被更新的写入切断。

我正在寻找一种排队写入文件的方法,这个系统/功能/流很容易包含和调用。

奖励积分:每当我尝试编写std :: string和Fstring时,ofstream似乎都会抱怨:|

3 个答案:

答案 0 :(得分:1)

使用ie g2log或使用非阻塞套接字包装器异步记录,例如zeromq

答案 1 :(得分:0)

ofstream不能跨多个线程使用。它需要使用互斥锁或类似对象进行同步。请查看以下主题以获取详细信息:ofstream shared by mutiple threads - crashes after awhile

答案 2 :(得分:0)

我写了一个快速的例子,说明如何实现这样的东西。请记住,这可能不是最终解决方案,仍然需要额外的错误检查等等......

#include <concurrent_queue.h>
#include <string>
#include <thread>
#include <fstream>
#include <future>

class Message
{
public:
    Message() : text_(), sender_(), quit_(true) 
    {}
    Message(std::string text, std::thread::id sender)
        : text_(std::move(text)), sender_(sender), quit_(false)
    {}

    bool isQuit() const { return quit_; }
    std::string getText() const { return text_; }
    std::thread::id getSender() const { return sender_; }

private:
    bool quit_;
    std::string text_;
    std::thread::id sender_;
};


class Log
{
public:
    Log(const std::string& fileName)
        : workerThread_(&Log::threadFn, this, fileName)
    {}
    ~Log()
    {
        queue_.push(Message()); // push quit message
        workerThread_.join();
    }

    void write(std::string text)
    {
        queue_.push(Message(std::move(text), std::this_thread::get_id()));
    }

private:
    static void threadFn(Log* log, std::string fileName)
    {
        std::ofstream out;
        out.open(fileName, std::ios::out);
        assert(out.is_open());
        // Todo: ... some error checking here

        Message msg;
        while(true)
        {
            if(log->queue_.try_pop(msg))
            {
                if(msg.isQuit()) 
                    break;
                out << msg.getText() << std::endl;
            }
            else
            {
                std::this_thread::yield();
            }
        }
    }

    concurrency::concurrent_queue<Message> queue_;
    std::thread workerThread_;
};


int main(int argc, char* argv[])
{
    Log log("test.txt");
    Log* pLog = &log;

    auto fun = [pLog]()
    {
        for(int i = 0; i < 100; ++i)
            pLog->write(std::to_string(i));
    };

    // start some test threads
    auto f0 = std::async(fun);
    auto f1 = std::async(fun);
    auto f2 = std::async(fun);
    auto f3 = std::async(fun);

    // wait for all
    f0.get();
    f1.get();
    f2.get();
    f3.get();

    return 0;
}

主要思想是使用一个具有线程安全write()方法的Log类,该方法可以同时从多个线程调用。 Log类使用工作线程将所有文件访问权限放到另一个线程。它使用线程安全(可能是无锁)数据结构将所有消息从发送线程传输到工作线程(我在这里使用concurrent_queue - 但也有其他消息)。使用一个小的Message包装器,告诉工作线程关闭非常简单。然后加入它,一切都很好。 只要可能写入的任何线程仍在运行,就必须确保不销毁日志。