C++ - 如何让多个线程写入同一个文件

10
我正在编写一个C++程序,使用线程向文件中写入字符串。我正在使用ofstream来写这些字符串,但我发现只有一个线程可以访问该文件。
所以我的问题是:是否有办法在不同的线程中使用ofstream来写入同一个文件?
如果可能,提供一些示例代码会很好。如果不行,请告诉我并指出一些解决方法也将不胜感激。 我看了下面的链接,但它对我来说并没有太多意义: 如果所有线程都写入到不同的位置,那么多个线程可以同时写入文件吗?

通常情况下,IO是多线程的瓶颈。让多个线程写入同一个文件通常是不希望的。你可以使写入同步,但此时你并没有得到期望的效果。 - erip
@Zboson 根据我所了解的有限信息,btrfs 是基于 B 树的,因此它无论如何都不会线性访问数据。然而,文件系统不会写入同一个文件 - 它们将写入同一系统中的多个文件,因此您可以实现某些操作的加速。 - erip
2个回答

21

一种方法是创建一个包装文件的单个对象,然后将对这个包装器对象的引用提供给需要写入文件的所有对象。在这个包装类内部,对文件的写入是同步的,以便只有一个写入者可以提交要写入的数据(即一个写入者完成写入之前,其他写入者不能写入)。例如:

class SynchronizedFile {
public:
    SynchronizedFile (const string& path) : _path(path) {
        // Open file for writing...
    }

    void write (const string& dataToWrite) {
        // Write to the file in a synchronized manner (described below)...
    }

private:
    string _path;
};

class Writer {
public:
    Writer (std::shared_ptr<SynchronizedFile> sf) : _sf(sf) {}

    void someFunctionThatWritesToFile () {
        // Do some work...
        _sf->write("Some data to write...");
    }
private:
    std::shared_ptr<SynchronizedFile> _sf;
};

使用这些写入器的客户端代码将类似于以下内容:

// Create the synchronized file
auto synchronizedFile = std::make_shared<SynchronizedFile>("some/file.txt");

// Create the writers using the same synchronized file
Writer writer1(synchronizedFile);
Writer writer2(synchronizedFile);

使用这种方法,一个单一的对象(类型为SynchronizedFile)来管理文件,并且所有的写操作都是通过这个对象进行管理的。现在,为了确保只有一个线程可以使用write(const string&),需要使用std::lock_guard这个锁机制。使用这个锁定机制,SynchronizedFile的实现将类似于:

class SynchronizedFile {
public:
    SynchronizedFile (const string& path) : _path(path) {
        // Open file for writing...
    }

    void write (const string& dataToWrite) {
        // Ensure that only one thread can execute at a time
        std::lock_guard<std::mutex> lock(_writerMutex);

        // Write to the file...
    }

private:
    string _path;
    std::mutex _writerMutex;
};

因为似乎写入文件不是您的问题,我已经将打开和写入留给您去实现,但上面的片段显示了同步写入的基本结构。如果您在打开和写入文件时遇到问题,请告诉我,我可以帮您解决。

注意:上述片段使用C ++ 11结构。如果您无法使用C ++ 11,请告诉我,我们可以考虑使用C ++ 98(或其他库/ API)来实现相同的结果。


这里我没有看到任何线程,我有什么遗漏吗?比如在不同的线程中启动编写或写入类函数。 - user3792685
@user3792685 正确。以上内容不包括线程本身。相反,SynchronizedFile类仅显示了如何包装文件,以便它可以被多个线程使用而不会导致线程争用。将SynchronizedFile对象注入到单独的线程中的任务被省略以增加清晰度。 - Justin Albano
我无法确定应该在哪里创建 fstream 对象以及在哪里写入文件?你能解释一下吗? - Shahriar.M

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接