みんなの「教えて(疑問・質問)」にみんなで「答える」Q&Aコミュニティ

こんにちはゲストさん。会員登録(無料)して質問・回答してみよう!

解決済みの質問

自動実行について

こんばんは。
大変お世話になっております。
Visual C++.NETを用いてコンソール上でwinsockでソケットプログラミングを行っています。言語はC言語とWIN32APIを用いています。以下に示す動作を複数回、自動実行?というのでしょうか・・・は可能でしょうか?

1.ファイルオープンとメイン内でスレッドAとスレッドBを生成(マルチスレッド)です。この際、スレッドAでソケット1オープンし、スレッドBでソケット2をオープンしています
2.ファイルに取得値を書き込み
3.スレッドAとB内でソケットクローズ
4.メイン内でファイルクローズとCloseHandle関数にてスレッドA・B終了

1~4の内容を自動実行させたいのですが、なにか方法はあるのでしょうか?バッチファイルをあてると聞いたことがあるのですが、作り方が分からないのでお聞きしたしだいです。

よろしくお願い致します。

投稿日時 - 2007-01-31 18:46:23

QNo.2712241

困ってます

質問者が選んだベストアンサー

始めに誤解のないように言っておきますが、No2 の回答と No3 の回答は、それぞれ別の実現手段です。No2の方法とNo3の方法を組み合わせるというわけではないので、あしからず。


スレッド間の同期を取らなければならない点を考えると、No2の方法はスレッドA,Bの終了をメインが待っていればいいだけなので、こちらのほうが実装が比較的簡単になりそうな気がします。
指定回数だけ繰り返すなら、メインの処理は

HANDLE hThread[2];
for (i=0, i<回数, i++) {
 hThread[0] = (HANDLE)_beginthreadex(省略); //スレッドA作成
 hThread[1] = (HANDLE)_beginthreadex(省略); //スレッドB作成
 WaitForMultipleObjects(2,hThread,TRUE,INFINITE); //A,B両方が終了するのを待つ
 CloseHandle(hThread[0]); //スレッドA破棄
 CloseHandle(hThread[1]); //スレッドB破棄
}

のような形になります(実際にはエラーチェック等が必要ですが)。
スレッドAおよびBの関数での処理はソケットからの読み込みとファイルへの書き込みを行うだけです。
ファイルオープン・クローズやソケット接続をどこで行うかについては処理内容にもよりますが。


一方、No3の回答にあるイベントを使う方法では、
・メインがスレッドAに処理開始を要求するイベント
・メインがスレッドBに処理開始を要求するイベント
・スレッドAがメインに処理完了を通知するイベント
・スレッドBがメインに処理完了を通知するイベント
の4つのイベントを使うことになります。
ちなみにこれは「自動リセットイベント」という種類のイベントオブジェクトを使用することを前提にしていて、手動リセットイベントを使ったり、うまくフラグを使ったりすれば使用するイベントの数を減らすこともできると思いますが、混乱の元なので説明は省きます。
メインの大まかな処理は

HANDLE hEvtMtoA, hEvtMtoB, hEvtAtoM[2]; //(グローバル変数)

HANDLE hThread[2];
hThread[0] = (HANDLE)_beginthreadex(省略); //スレッドA作成
hThread[1] = (HANDLE)_beginthreadex(省略); //スレッドB作成
hEvtToA = CreateEvent(NULL,FALSE,FALSE,NULL); //Main→A通知Event
hEvtToB = CreateEvent(NULL,FALSE,FALSE,NULL); //Main→B通知Event
hEvtToM[0] = CreateEvent(NULL,FALSE,FALSE,NULL); //A→Main通知Event
hEvtToM[1] = CreateEvent(NULL,FALSE,FALSE,NULL); //B→Main通知Event
for (i=0, i<回数, i++) {
 SetEvent(hEvtToA); // Aに処理開始要求
 SetEvent(hEvtToB); // Bに処理開始要求
 WaitForMultipleObjects(2,hEvtAtoM,TRUE,INFINITE); //A,Bの処理完了待ち
}
EndFlag = TRUE; // プログラム終了フラグ
SetEvent(hEvtToA); // 終了させるためイベントでスレッドAを起こす
SetEvent(hEvtToB); // 終了させるためイベントでスレッドBを起こす
WaitForMultipleObjects(2,hThread,TRUE,INFINITE); //A,Bのスレッド終了待ち
CloseHandle(hThread[0]); //スレッドA破棄
CloseHandle(hThread[1]); //スレッドB破棄

また、スレッドAの処理は

while (TRUE) {
 WaitForSingleObject(hEvtToA,INFINITE); //メインからの通知待ち
 if (EndFlag) break;// プログラム終了時にループ抜ける
 ソケット処理・ファイル書き込み処理
 SetEvent(hEvtAtoM[0]); // メインに処理完了を通知
}

という感じになります (こちらもエラー処理省略)。
スレッドBも同様です (hEvtToA→hEvtToB, hEvtAtoM[0]→hEvtAtoM[1] に変える)。


ところで、
> スレッドBがAより遅く終わるため
という記述が気になったのですが…AとBの処理は互いに独立しているというわけではないのでしょうかね。

投稿日時 - 2007-02-03 00:41:39

このQ&Aは役に立ちましたか?

0人が「このQ&Aが役に立った」と投票しています

回答(5)

ANo.5

再び記述ミス、hEvtToM を hEvtAtoM と書いてしまっている部分がありました。

投稿日時 - 2007-02-03 00:45:07

お礼

ご返答ありがとうございます。
大変詳しい解説、とても参考になります。

> スレッドBがAより遅く終わるため
>という記述が気になったのですが…AとBの処理は互いに独立している >というわけではないのでしょうかね。
そういうことです。

実は、スレッドAをパケット送信スレッド。スレッドBをパケット受信スレッドとしていました。そこで、スレッドBはとある文字列を持つパケットを受信すれば終了としていたため、ソレッドBがスレッドAより遅く終わるという仕様にしていました。

そのため、
スレッドB終了→スレッドA終了→メイン処理終了としていました。
でも、教えていただいたWaitForMultipleObjectsをメイン内に記述しておけば、簡易にできることを知りました。

まだ、少しだけ疑問点もあるのですが、No2の方法を用いて解決しました。

ありがとうございました。

投稿日時 - 2007-02-05 02:30:37

ANo.3

WaitForMultipleObjects を間違えて WaitForMultipleThread と書いてしまいました、失礼。


毎回スレッドの作成・破棄を繰り返すのではなく、最初に一度だけスレッドA,Bを作成し、それを使い続けるという方法もありますね。
その場合はイベントを使用してスレッド間の同期を取る必要があります。
CreateEvent, SetEvent で検索するといろいろと出てくると思います。

投稿日時 - 2007-02-01 23:46:28

補足

返信ありがとうございます。
WaitForMultipleObjectsではありませんが、WaitForSingleObjectを利用して、tea_sheepさんのおっしゃるとおり、SetEvent等を用いて同期をとるプログラムを作成しています。まだ、自動実行処理?は未実装です。

以下に示すようなプログラムを記述しています。
メイン内に記述した(1)~(6)が大まかな動作手順です。前回記述した内容と代わりがないのですが・・・
スレッドBがAより遅く終わるため、SetEvent関数WaitForSingleObject関数を用いて同期をとっています。

ここで、分からない点があるのですが、
>スレッドA,Bを最初に生成し、それを使い続ける場合スレッドの同期を>取る必要がある。
とのことですが・・・

WaitForSingleObject関数を用いて待機しているところを、SetEvent関数で呼びだすということでしょうか?

WaitForSingleObject関数を用いた場合、SetEvent関数で呼ばれるまで待機状態のままのような気がしたのです。メイン内の(5)終了後に、なにか処理を行うことで可能なのでしょうか?

よろしくお願い致します。

//グローバル変数
HANDLE hEvent[4];
FILE *fp1,fp2;

[スレッドB]
SetEvent(hEvent[0]);

[スレッドA]
WaitForSingleObject(hEvent[0],INFINITE);
SetEvent(hEvent[1]);

[メイン]
(1)ファイルオープン
(2)_beginthreadex関数にてスレッドA,Bを生成。
 スレッドAとBが動作します。
(3)WaitForSingleObject(hEvent[1],INFINITE)にて、メイン内でスレッドAを待機していますが、スレッドAのイベントにて待機→再開されます
(4)スレッドA,B破棄
(5)ファイルクローズ
(6)プログラム終了

投稿日時 - 2007-02-02 18:03:24

ANo.2

スレッドを作成した後でそのスレッドが終了するまで待機するには WaitForSingleObject や WaitForMultipleObjects を使うことができます。
メインスレッドでは、新しいスレッドを作成した後でこれらの関数を使用してスレッド終了を待つ、という動作をfor文などで繰り返せばよいと思います。

メインスレッドでは以下 1.~3. を回数分だけ繰り返します。
1. CreateThread でスレッドA,Bを作成
2. WaitForMultipleThread で、スレッドA,Bが共に終了したときに再開するように指定
 (... スレッド終了まで待機...)
3. CloseHandle でスレッドA, B のハンドルをクローズする

ところで、作成したスレッドでCランタイム関数を使用する場合、そのスレッド作成に CreateThread を使用するとメモリリークを起こす可能性があります。
それを防ぐためには CreateThread の代わりに _beginthreadex を使います (戻り値をHANDLE型にキャストする必要があります)。
自分が作成するスレッドの関数内でCランタイム関数を使用していなくても、ソケット関連の関数が使用している可能性もありますから、_beginthreadex を使うほうが良いかもしれません。

投稿日時 - 2007-02-01 23:41:23

ANo.1

自動実行というのは、どのように実行させることを言うのでしょう?
決まった回数だけ連続して繰り返すのか、ある時刻になったら実行するのか、一定時間ごとに定期的に実行するのか、それとも、別にトリガーとなるイベントがあるのでしょうか。

投稿日時 - 2007-01-31 23:37:56

補足

返信ありがとうございます。
決まった回数(10回ほど)を連続して繰り返すことを考えたいと思っています。

1.ファイルオープンとメイン内でスレッドAとスレッドBを生成(マルチスレッド)です。この際、スレッドAでソケット1オープンし、スレッドBでソケット2をオープンしています
2.ファイルに取得値を書き込み
3.スレッドAとB内でソケットクローズ
4.メイン内でファイルクローズとCloseHandle関数にてスレッドA・B終了

1から4の流れを1回と考えこれを、10回行いたいと思っています。
よろしくお願い致します。

投稿日時 - 2007-02-01 13:33:18

あなたにオススメの質問