5

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() が 2 つの異なるスレッドによって同時に実行される可能性があります。上記のスレッドセーフにする方法はありますか?

ファイルロック( fcntl および/または lockf )の使用を検討しましたが、アプリケーションで fopen() が使用されているため(パフォーマンス上の理由)、それらのファイルロックを使用すべきではないことがどこかに記載されているため、それらの使用方法がわかりませんfopen を使用 (バッファリングされているため)

PS : 関数 foo_one() と foo_two() は 2 つの異なるクラスにあり、それらの間でデータを共有する方法はありません :( 。悲しいことに、1 つの関数が他の関数を呼び出すことができないように設計されています。

4

5 に答える 5

8

ロギング機能を追加。
どちらの関数もロギング関数を呼び出します (適切なロックを行います)。

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

    // open("abc.txt");
    // write msg
    // close
}
于 2012-10-15T05:37:19.530 に答える
2

本当にロガーが必要な場合は、単純にファイルに書き込もうとするのではなく、おそらく専用のロガーを使用して、作成中のコードから問題を切り離してください。スレッドセーフなロガーはたくさんありますが、最初に頭に浮かぶのはg2logです。さらにグーグルで検索すると、 log4cplus 、ここでの議論、さらにはミニマリストの議論、+ 1 が見つかります。

于 2012-10-15T05:36:16.297 に答える
1

関数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);
}

もちろん、これはこれらが唯一のライターであることを前提としています。他のスレッドまたはプロセスがファイルに書き込む場合は、ロック ファイルを使用することをお勧めします。

于 2012-10-15T05:24:57.417 に答える
1

これを行う必要があります。mutex と ofstream を持つ構造体を用意します。

struct parser {
    ofstream myfile
    mutex lock
};

次に、この構造体 (a) を foo1 と foo2 に void* として渡すことができます。

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 関数についても同じことができます。これにより、スレッドセーフな方法で同じファイルに書き込むことができます。

于 2012-10-15T05:33:06.927 に答える
0

このコードを試してください。私は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;
}

参考:

于 2016-07-14T13:53:03.930 に答える