【问题标题】:Writing (logging) into same file from different threads , different functions?从不同的线程,不同的功能写入(记录)到同一个文件?
【发布时间】:2012-10-05 01:44:30
【问题描述】:

在 C++ 中,有没有办法在以下情况下使写入文件线程安全?

void foo_one(){
lock(mutex1);
//open file abc.txt
//write into file
//close file
unlock(mutex1);
}

void foo_two(){
lock(mutex2);
//open file abc.txt
//write into file
//close file
unlock(mutex2);
}

在我的应用程序(多线程)中,foo_one() 和 foo_two() 很可能同时由两个不同的线程执行。 有什么方法可以使上述线程安全吗?

我考虑过使用文件锁( fcntl 和/或 lockf ),但不确定如何使用它们,因为 fopen() 已在应用程序中使用(性能原因),并且在某处说明这些文件锁应该不能与 fopen 一起使用(因为它是缓冲的)

PS : 函数 foo_one() 和 foo_two() 位于两个不同的类中,它们之间无法共享数据:( 遗憾的是,设计使得一个函数不能调用另一个函数。

【问题讨论】:

  • 是的。您只需要一个代表文件的锁(称为 mutex3)。 PS。如果您正在编写 C++ 代码,您应该使用 RAII 来锁定/解锁这些互斥锁。
  • @LokiAstari 函数 foo_one() 和 foo_two() 位于两个不同的类中,它们之间无法共享资源:( 遗憾的是,设计使得一个函数不能调用其他函数。
  • 可以只创建一个类的“Write”函数,在它自己的线程上调用它。只是循环直到它退出。然后每次你需要写东西到文件时,你可以把它推到向量中,让那个线程在它到达后立即将它写到文件中。

标签: c++ multithreading file logging


【解决方案1】:

添加记录功能。
这两个函数都调用日志记录函数(执行适当的锁定)。

mutex  logMutex;
void log(std::string const& msg)
{
    RAIILock  lock(logMutex);

    // open("abc.txt");
    // write msg
    // close
}

【讨论】:

  • 如果性能是一个问题,锁定可能不是 k0n3ru 可能想要的。
  • @devopsEMK:它是对使用RAII 锁定/解锁另一个对象的类的通用引用。它们很容易写。一个例子是std::lock_guard
【解决方案2】:

如果您确实需要记录器,请不要尝试仅通过写入文件来实现它,并且可能使用专用记录器,从而将关注点与您正在编写的代码分开。有许多线程安全的记录器:首先想到的是:g2log。进一步谷歌搜索你会发现log4cplus,一个讨论here,甚至一个minimalist one+1

【讨论】:

    【解决方案3】:

    如果函数foo_one()foo_two()的本质只是打开文件,写一些东西,然后关闭它,然后使用相同的互斥锁来防止它们相互混淆:

    void foo_one(){
      lock(foo_mutex);
      //open file abc.txt
      //write into file
      //close file
      unlock(foo_mutex);
    }
    
    void foo_two(){
      lock(foo_mutex);
      //open file abc.txt
      //write into file
      //close file
      unlock(foo_mutex);
    }
    

    当然,这是假设这些是唯一的作者。如果其他线程或进程写入该文件,锁定文件可能是个好主意。

    【讨论】:

    【解决方案4】:

    你应该这样做,有一个带有互斥体和 ofstream 的结构:

    struct parser {
        ofstream myfile
        mutex lock
    };
    

    然后你可以把这个结构体 (a) 作为一个 void* 传递给 foo1 和 foo2

    parser * a = new parser();
    

    初始化互斥锁,然后你可以将结构传递给这两个函数。

    void foo_one(void * a){
         parser * b = reinterperet_cast<parser *>(a);
         lock(b->lock);
             b->myfile.open("abc.txt");
             //write into file
             b->myfile.close();
          unlock(b->mutex);
    }
    

    您可以对 foo_two 函数执行相同的操作。这将提供一种线程安全的方法来写入同一个文件。

    【讨论】:

    • 虽然这种方法“有效”并且您的答案写得很好,但您只需要了解如何使用 RAII 跟踪互斥锁。
    【解决方案5】:

    试试这个代码。我已经用 MFC 控制台应用程序

    #include "stdafx.h"
    #include <mutex>
    
    CWinApp theApp;
    using namespace std;
    
    
    const int size_ = 100; //thread array size
    std::mutex mymutex;
    void printRailLock(int id) {
        printf("#ID :%", id);
        lock_guard<std::mutex> lk(mymutex); // <- this is the lock
        CStdioFile lastLog;
        CString logfiledb{ "_FILE_2.txt" };
        CString str;
        str.Format(L"%d\n", id);
        bool opend = lastLog.Open(logfiledb, CFile::modeCreate | CFile::modeReadWrite | CFile::modeNoTruncate);
        if (opend) {
            lastLog.SeekToEnd();
            lastLog.WriteString(str);
            lastLog.Flush();
            lastLog.Close();
        }
    }
    int main()
    {
        int nRetCode = 0;
        HMODULE hModule = ::GetModuleHandle(nullptr);
    
        if (hModule != nullptr)
        {       
            if (!AfxWinInit(hModule, nullptr, ::GetCommandLine(), 0))
            {            
                wprintf(L"Fatal Error: MFC initialization failed\n");
                nRetCode = 1;
            }
            else
            {
                std::thread threads[size_];
                for (int i = 0; i < size_; ++i) {
                    threads[i] = std::thread(printRailLock, i + 1);
                    Sleep(1000);
                }
                for (auto& th : threads) { th.hardware_concurrency(); th.join(); }
            }
        }
        else
        {       
            wprintf(L"Fatal Error: GetModuleHandle failed\n");
            nRetCode = 1;
        }
    
        return nRetCode;
    }
    

    参考:

    【讨论】:

      猜你喜欢
      • 2023-03-21
      • 1970-01-01
      • 2013-03-06
      • 2012-10-18
      • 1970-01-01
      • 1970-01-01
      • 2018-11-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多