C++ - How to have multiple threads write to a file

Flare Cat picture Flare Cat · Nov 8, 2015 · Viewed 14.6k times · Source

I am currently writing a c++ program that uses threads to write strings to a file. I am using ofstream to write these strings, and I noticed that only one of the threads has access to the file.

So my question: Is there any way to use ofstream in different threads to write to the same file?

If it is possible, any examples would be great. If not, please let me know that as well, and some ways to get around this would be great. I have looked at the following link, except it didn't really make sense to me: Can multiple threads write into a file simultaneously, if all the threads are writing to different locations?

Thanks in advance!

Answer

Justin Albano picture Justin Albano · Nov 8, 2015

One approach is to create a single object that wraps the file and then provide a reference to this wrapper object to all objects that need to write to the file. Within this wrapper class, writing to the file is synchronized so that only one writer can submit data to be written at a time (i.e., one writer will complete before another, or the same writer, can write). For example:

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;
};

The client code that uses these writers would resemble the following:

// 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);

Using this approach, a single object (of type SynchronizedFile) manages the file and all writing is managed through this object. Now, in order to ensure that only one thread can use the write(const string&), a std::lock_guard. Using this locking mechanism, the implementation for the SynchronizedFile would resemble:

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;
};

Since it appears as though writing to a file is not your issue, I have left the opening and writing to you to implement, but the above snippet shows the basic structure for synchronizing the writing. If you have issues opening and writing to the file, let me know and I can flush that out for you.

Note: The above snippets use C++11 structures. If you cannot use C++11, let me know and we can look at using C++98 (or other libraries/APIs) to achieve the same results.