DLL 関数スレッド内ファイル書き込みの排他制御について – プログラミング – Home

DLL 関数スレッド内ファイル書き込み...
 
通知
すべてクリア

[解決済] DLL 関数スレッド内ファイル書き込みの排他制御について


なおぞう
 なおぞう
(@なおぞう)
ゲスト
結合: 9年前
投稿: 143
Topic starter  

お世話になります。
VS2013 標準Windowsライブラリを使用、Unicode文字セットを使用、共通言語ランタイム
サポートをしない の環境でDLLを作成しております。

排他制御を考えないで、DLL内の関数と、そこで生成したスレッド1(スレッド1の中で
さらにスレッド2を生成)3つの関数の中でそれぞれログ出力させています。
スレッド1の最初のログ出力処理でファイルオープンエラーが発生し、それ以降スレッド
関数の処理が停止していることに気がつき、排他処理を入れればよいと思い、調べたので
すが、

APIの同期オブジェクトは
・ミューテックス
・セマフォ
・タイマー
・イベント
・クリティカルセクション

いろいろあるようで何を使うのが良いのか分からず、サンプルを探しても、
①ファイルに書き込もうとして、他のが書きこんでいたら待たせておく
②終わったら書きこませる
というものが見つからなくてアドバイスをいただきたく書きこませていただいておりま
す。よろしくお願いします。

----排他制御が組み込まれていないテストプログラム-----
unsigned __stdcall ThreadTest(PVOID p)
{
FILE* fp;
TCHAR acMsg[512];
memset(acMsg, '\0', sizeof(acMsg));
swprintf_s(acMsg, 512, TEXT(C:\\TestLog\\DllThread.txt));

for (int i = 0; i < 10; i++){
_wfopen_s(&fp, acMsg, TEXT(a+));
if (fp == NULL){ printf(THREAD FILE POINTER IS NULL\n); }
fwprintf_s(fp, LTHREAD %s\n, acMsg);
fclose(fp);
}
return 1;
}

EXPORT DWORD WINAPI LOGPRINT()
{
FILE* fp;
TCHAR acMsg[512];
memset(acMsg, '\0', sizeof(acMsg));
swprintf_s(acMsg, 512, TEXT(C:\\TestLog\\DllThread.txt));

//処理スレッドを起動する(スレッドの生成)
unsigned int threadID;
DWORD exitcode;
HANDLE hThread = (HANDLE)_beginthreadex(0, 0U, ThreadTest, (void*)0, 0, &threadID);

for (int i = 0; i < 10; i++){
_wfopen_s(&fp, acMsg, TEXT(a+));
if (fp == NULL){ printf(MAIN FILE POINTER IS NULL\n); }
fwprintf_s(fp, LMAIN %s\n, acMsg);
fclose(fp);
}
GetExitCodeThread(hThread, &exitcode);
CloseHandle(hThread);
return 1;
}

-------------------
上記プログラムでは、LOGPRINT()関数のファイル出力処理と、ThreadTest()でのファイ
ル出力処理が競合してしまい、ThreadTest()の方がファイルオープンエラーで終わってし
まうようです。

このコードをどのように改造すれば排他制御ができ、ThreadTestでのログ出力ができるよ
うになるのでしょうか。
ファイルオープンの仕方からしてまるっきり変えることになるのでしょうか?

教えていただけますようお願いします。


引用未解決
トピックタグ
tetrapod
 tetrapod
(@tetrapod)
ゲスト
結合: 21年前
投稿: 830
 

そういう「ログ」機能を実装する際には、

・出力したいログを受け付けるルーチンは、メッセージを FIFO に登録するだけ
(ここで排他する)

・ FIFO からファイルへの出力は1箇所で行う(排他不要)

という感じで実装するものだと思う。

# 何度も指摘してるけどスレッドが終わる前に GetExitCodeThread しても意味がない。


返信引用
瀬戸っぷ
 瀬戸っぷ
(@瀬戸っぷ)
ゲスト
結合: 18年前
投稿: 178
 

>①ファイルに書き込もうとして、他のが書きこんでいたら待たせておく
>②終わったら書きこませる
>というものが見つからなくてアドバイスをいただきたく書きこませていただいておりま
>す。よろしくお願いします。

クリティカルセクションでいいんじゃないですか?
「待たせておく」が簡単にできるようですし。

https://msdn.microsoft.com/ja-jp/library/cc429095.aspx
>指定されたクリティカルセクションオブジェクトの所有権を取得するまで待機します。


返信引用
AR2
 AR2
(@ar2)
Estimable Member
結合: 5年前
投稿: 110
 

 設計の考え方としては、tetrapodさんの意見を私も推しますね。

 タイマーとイベントに関しては論外なので省略します。
 クリティカルセクションと、ミューテックスと、セマフォの3択になりますが、ログを
吐く程度の用途ならセマフォは候補から外れます。
 クリティカルセクションとミューテックスの使い分けは、同期オブジェクトのインスタ
ンス数で考えるので、どちらでも実現可能です。
 クリティカルセクションの方が実装は簡単ですが、プロセスをまたいだりということは
不可能になります。

 ログ出力関数がDLLの中にあって、別exeから呼ばれるならミューテックスということに
なります。
 さっくりまとめられてるサイトがありましたのでどうぞ。
http://tecopark.blogspot.jp/2012/04/winapi.html


返信引用
なおぞう
 なおぞう
(@なおぞう)
ゲスト
結合: 9年前
投稿: 143
Topic starter  

>みなさま

いろいろとアドバイスありがとうございました。
あまり美しくない方法で解決させてしまいました。
_wfopen_s(&fp, acMsg, TEXT(a+)); が、共有不可でOPENしているので、競合する
とfpがNULLになります。
fp==NULLの間だけwhile(1)でまわして!=NULLになるまでopenをする。
という方法です。(タイムアウト設定あり)
原始的というべきでしょうか。

FIFOを使ってみたいと思ったのですが、どうやったら良いのか分からず時間もなくてこの
ような対応になってしまいました。

>tetrapod 様
># 何度も指摘してるけどスレッドが終わる前に GetExitCodeThread しても意味がない。

スレッドの終了を待たない仕様なので、GetExitCodeThreadは意味が無いのですがなんと
なく書いてしまうのです。


返信引用
なおぞう
 なおぞう
(@なおぞう)
ゲスト
結合: 9年前
投稿: 143
Topic starter  

クローズ忘れました。


返信引用
瀬戸っぷ
 瀬戸っぷ
(@瀬戸っぷ)
ゲスト
結合: 18年前
投稿: 178
 

ちなみにスレッド生成の手順は?
以前にどなたかが指摘していたと思いますので大丈夫だとは思いますが。


返信引用
なおぞう
 なおぞう
(@なおぞう)
ゲスト
結合: 9年前
投稿: 143
Topic starter  

>瀬戸っぷさま

以下のように書いてますが…間違ってますか。

DWROD Function1(){

unsigned int threadID;
DWORD exitcode;
HANDLE hThread = (HANDLE)_beginthreadex(0, 0U, TreadTest, (PVOID)FUNC, 0,&threadID);
if (hThread == 0)
{
return 0;
}

GetExitCodeThread(hThread, &exitcode); //←これが意味無しですが。
CloseHandle(hThread);

return 1;//スレッドの終了を待たないで処理を返す
}

unsigned __stdcall TreadTest(PVOID p)
{

PFUNC pfunc = (PFUNC)p;
:
処理(さらにスレッド立ち上げたり)
:
pfunc(error);
return error;
}


返信引用
瀬戸っぷ
 瀬戸っぷ
(@瀬戸っぷ)
ゲスト
結合: 18年前
投稿: 178
 

_beginthreadex()なら問題ないです。

CreateThread()だと駄目でしたけど。


返信引用
なおぞう
 なおぞう
(@なおぞう)
ゲスト
結合: 9年前
投稿: 143
Topic starter  

>瀬戸っぷ様

最初はCreateThreadを使っていたのですが、余りよろしくないという書き込みを見て
_beginthreadex()に変更しました。

わざわざ確認していただきありがとうございます。


返信引用

返信する

投稿者名

投稿者メールアドレス

タイトル *

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