I have a simple class in C++20 that logs data to a file line by line for Windows platform. To ensure thread safety, I use a static std::mutex to serialize the write operations.
However, I encounter an issue: if I don't explicitly call flush after each write while holding the lock, some lines are missing in the output file. When I call flush, all lines are correctly written to the file.
Here’s a simplified version of the code:
class Logger {
public:
void Log(const std::string& message) {
std::lock_guard lock(mtx_);
log_file_ << std::format("{}\n", message);
// log_file.flush(); // Uncommenting this works fine
}
private:
static std::mutex mtx_;
std::ofstream log_file_{ "log.txt", std::ios::app };
};
std::mutex Logger::mtx_;
int main()
{
std::vector<std::future<void>> futures;
// Launch the function asynchronously
for (int i = 0; i < 25; ++i) {
futures.push_back(std::async(std::launch::async, []() {
Logger logger;
logger.Log("Test message"); }));
}
// Wait for all tasks to complete
for (auto& future : futures) {
future.get();
}
}
Why does this happen? Why doesn't the operating system automatically handle flushing the output when it's serialized using a mutex, without explicitly calling flush?
Is this expected behavior for file streams in C++?
flush()or waiting for the completion of operating system calls.ofstreamis typically line-buffered and flushes automatically on\n.flushexists for handling streams that are not line-buffered, or when you want manual flushing. In any case, yourlog_file_is notstaticso you are repeatedly opening and closing the file outside of your lock.