マルチスレッドでのファイル書き込み – プログラミング – Home

マルチスレッドでのファイル書き込み
 
通知
すべてクリア

マルチスレッドでのファイル書き込み


wind
 wind
(@wind)
ゲスト
結合: 23年前
投稿: 10
Topic starter  

こんにちわ、windです。

マルチスレッド(DLLで)にて質問があります。
マルチスレッドで同じファイルに書き込みを行うのですが、順番待ちの仕方がわかりません。
下のようなソースを使用しているのですが、タイミングによっては同時に書き込まれてファイル
のフォーマットが乱れてしまします。
環境はWin2000、MSのVC++6.0です。
できればMFCを使用しない方法でご教授ください。

void LogWrite(char *strLog)
{

BOOL bFlag=TRUE;
BOOL bCreated=TRUE;

HANDLE hSyn = CreateSemaphore(NULL,1,1,SEMPHORE_NAME);
if ( !hSyn || hSyn != INVALID_HANDLE_VALUE )
{
bFlag = FALSE;
}
else
{
if (GetLastError() == ERROR_ALREADY_EXISTS )
bCreated =FALSE;
}
if (bFlag)
{
WaitForSingleObject(hSyn, INFINITE);
}


ファイル書き込み処理
ファイル書き込み処理
ファイル書き込み処理
ファイル書き込み処理


if (bFlag)
{
ReleaseSemaphore(hSyn,1,NULL);
if (!bCreated)
{
CloseHandle(hSyn);
}
}
}


引用解決済
トピックタグ
wood
 wood
(@wood)
ゲスト
結合: 23年前
投稿: 895
 

>ファイル書き込み処理
の排他制御について聞きたいのではないのですか

つまり同時書き込みを防ぐには、どちらか一方で書き込み中はファイルロックする
必要があるのではないでしょうか


返信引用
YuO
 YuO
(@YuO)
ゲスト
結合: 24年前
投稿: 252
 

同期オブジェクトはグローバルに持たせた方が使いやすいです。

こんな感じかなぁ……。
namespace { // 外部からアクセスできないオブジェクト
class mutex_ { // Mutexの取得・解放を行うためのクラス
HANDLE hMutex;

// 複製は禁止
mutex_ (const mutex_ &);
mutex_& oeprator= (const mutex_ &);
public:
mutex_ (void);
~mutex_ (void);

bool wait (DWORD timeout = INFINITE) { return WaitForSingleObject(hMutex, timeout) == WAIT_OBJECT_0; }
bool release (void) { return ReleaseMutex(hMutex) != FALSE; }
} mutex;

mutex_::mutex_ (void) : hMutex(CreateMutex(NULL, FALSE, NULL) {}
mutex_::~mutex_ (void) { CloseHandle(hMutex); }
}

void LogWrite (const char * strLog)
{
mutex.wait();

// ここで書き込み処理

mutex.release();
}

クラスを使いましたが,
最初に書き込まれるより前にMutexが作成され,
使い終わった後にMutexを解放できるならクラスを使う必要はありません。
#namespaceスコープのクラスオブジェクトの構築・解体でそれを保証しているだけです。
今回はMutexを使いましたが,Semaphoreでも同じです。
同期オブジェクトは,各スレッドごとに持つよりも,
グローバルに取ってしまった方が使いやすかったりします。


返信引用
アイススケーター
 アイススケーター
(@アイススケーター)
ゲスト
結合: 23年前
投稿: 280
 

クラスを利用しない場合

CreateMutex
OpenMutex
ReleaseMutex
CloseHandle

を利用すればいいですよ。


返信引用
wind
 wind
(@wind)
ゲスト
結合: 23年前
投稿: 10
Topic starter  

みなさん、お返事ありがとうございます。m(__)m
いろいろ試してみましたが、どうもうまくいきません。
単体でやると上手くいくんですが、同時に実行するとやはり化けます。
排他制御以外に何か原因があるのでしょうか?
よろしくお願いします。


返信引用
wood
 wood
(@wood)
ゲスト
結合: 23年前
投稿: 895
 

遅延書き込み(OS)
コミット、ファイルフラッシュ(PG)
この辺どんな処理してますか


返信引用
wind
 wind
(@wind)
ゲスト
結合: 23年前
投稿: 10
Topic starter  

ファイル書く関数は

MutexでWait

if ((hFile = CreateFile( Path,
#ifndef WINNT
GENERIC_WRITE ,
#else
FILE_APPEND_DATA | SYNCHRONIZE,
#endif
FILE_SHARE_DELETE|FILE_SHARE_READ|FILE_SHARE_WRITE,
NULL,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL
)) == INVALID_HANDLE_VALUE)
 {

#ifndef WINNT
sprintf(MsgBuf + strlen(MsgBuf),GetLastError = %d \n, GetLastError());
OutputDebugString(MsgBuf);
#endif
fprintf(strerr,Error CreateFile %s 0x%0x\n,ERRFILENAME,GetLastError());
fwrite( MsgBuf, 1, strlen(MsgBuf), strerr );
fflush( strerr );
}
else
{
#ifndef WINNT
SetFilePointer(hFile, 0,NULL, FILE_END);
#endif
if( ! WriteFile( hFile,MsgBuf,strlen(MsgBuf),&intLen, NULL))
{
fprintf( stderr, Error WriteFile %s 0x%0x\n,Path,GetLastError());
fwrite( MsgBuf, 1, strlen(MsgBuf), strerr );
fflush( strerr );
}

CloseHandle( hFile );
}



ReleaseMutex

という風になっています。
これ以外の処理は行っていません。
もし、何かあるようでしたご指摘願います。


返信引用
wood
 wood
(@wood)
ゲスト
結合: 23年前
投稿: 895
 

>CloseHandle( hFile );
の前に
BOOL FlushFileBuffers( HANDLE hFile);

いらないのでしょうか

fwriteに対してはfflushしているようですけど?


返信引用
wind
 wind
(@wind)
ゲスト
結合: 23年前
投稿: 10
Topic starter  

woodさんレスありがとうございます。
追加してみましてが駄目でした。

ログに書き出す際にsprintfを使って文字列を作成しているのですが、これは大丈夫なのでしょ
うか?
確かCreateThureadを使うときはstdio系の関数は使用不可だったような気がします。
サーバ側のDLLで複数クライアントから呼ばれる場合はどうなのでしょうか?


返信引用
YuO
 YuO
(@YuO)
ゲスト
結合: 24年前
投稿: 252
 

> 確かCreateThureadを使うときはstdio系の関数は使用不可だったような気がします。
> サーバ側のDLLで複数クライアントから呼ばれる場合はどうなのでしょうか?

DLLの場合,DllMainからはじめていて,
CRTとしてマルチスレッド用のものを使っていれば,問題なく使えます。

でもって,マルチスレッドということなので,
CreateMutex時に名前をNULLに指定しましたが,
複数のクライアントから呼ばれるのであれば,
何らかの名前を指定してすべてのDLLで同じMutexオブジェクトを共有する必要があります。
つまり,
> mutex_::mutex_ (void) : hMutex(CreateMutex(NULL, FALSE, NULL) {}
ここは
const char * const mutex_name = 2bd76e20-c5cb-11d6-968f-004026a7e5df; //さっき作ったUUID
mutex_::mutex_ (void) : hMutex(CreateMutex(NULL, FALSE, mutex_name) {}
のようにする必要があります。


返信引用
tetsu
 tetsu
(@tetsu)
ゲスト
結合: 23年前
投稿: 10
 

はじめまして tetsuと申します。

便乗質問になります。

環境は WIN2K VC6++ SP5 です。

興味があったので実験しようと思ったのですが、

> mutex_& oeprator= (const mutex_ &);
の部分で、error C2238: ';' の前に不正なトークンがあります。
と出てしまいます。

> // 複製は禁止
> mutex_ (const mutex_ &);
> mutex_& oeprator= (const mutex_ &);
その前に、上記では何をしているのか理解できないでいます。

何をしているのか、ご教授お願いします。

> mutex_::mutex_ (void) : hMutex(CreateMutex(NULL, FALSE, NULL) {}
mutex_::mutex_ (void) : hMutex(CreateMutex(NULL, FALSE, NULL)) {}

# )が抜けていたので訂正しておきます。

以上、よろしくお願いします。


返信引用
YuO
 YuO
(@YuO)
ゲスト
結合: 24年前
投稿: 252
 

> の部分で、error C2238: ';' の前に不正なトークンがあります。

私のミスですね……。
> mutex_& oeprator= (const mutex_ &);
mutex_& operator= (const mutex_ &);
^^

> その前に、上記では何をしているのか理解できないでいます。

コピーコンストラクタと代入演算子をprivateにしてさらに実装しないことで,複製できないようにしています。
複製できてしまうと,二つのインスタンスが同じハンドルを持ってしまい,問題が起きます。

コピーコンストラクタと代入演算子をprivateにして実装しないのは,オブジェクトの複製を禁止する一般的な方法です。


返信引用
tetsu
 tetsu
(@tetsu)
ゲスト
結合: 23年前
投稿: 10
 

tetsuです。

 YuOさんすばやい回答ありがとうございます。
 大変勉強になりました。
 mutexについていろいろ、勉強していきたいと思います。
 


返信引用

返信する

投稿者名

投稿者メールアドレス

タイトル *

プレビュー 0リビジョン 保存しました
共有:
タイトルとURLをコピーしました