- PR -

VS.NET2003 VC++ でのCreateThread使用。

1
投稿者投稿内容
りう。
会議室デビュー日: 2005/02/24
投稿数: 6
投稿日時: 2005-03-11 22:00
WindowsXP VS.NET2003 の環境でVC++をもちいて
win32アプリの改修を行っています。

元々のソースはVC++6.0で開発されたものですが、
ユーザーの指定により現在はVS.NET2003の環境に移行しようとしています。

このなかで
for(int i = 0;i <3;i++)
{
//スレッド起動処理
DWORD dwThreadId = 0L;
HANDLE hThread = CreateThread(NULL,0,MonitorThread,i,0,&dwThreadId);
//イベントログ出力1
}


中略

DWORD WINAPI MonitorThread(LPVOID lpParam)
{
//スレッド処理内容
//イベントログ出力2
}
という処理があるのですが、
3つのスレッド起動直後にスレッド処理内容のところで、
イベントログ出力2でlpParamの内容を
出力して確認すると値が全て2となっていました。

イベントログ出力をさせ処理順番を確認したところ、
イベントログ出力1が3回出力されたあとに
イベントログ出力2が3回されています。

この処理順では3回ともiの最後の値を用いて動くことになってしまいます。

以前のバージョンではこのような動きはしていなかったと思います。
バージョンの問題なのでしょうか?
また、この現象を回避する方法はあるのでしょうか?
ご教授お願いいたします。
甕星
ぬし
会議室デビュー日: 2003/03/07
投稿数: 1185
お住まい・勤務地: 湖の見える丘の上
投稿日時: 2005-03-11 22:26
引用:

りう。さんの書き込み (2005-03-11 22:00) より:
WindowsXP VS.NET2003 の環境でVC++をもちいて
win32アプリの改修を行っています。


生のAPIを呼んでいると言うことは、M
FCアプリケーションとして移植していると思ってよいですか?
引用:

3つのスレッド起動直後にスレッド処理内容のところで、
イベントログ出力2でlpParamの内容を
出力して確認すると値が全て2となっていました。


え゛〜コードを見る限り1,2,3と表示されると思うんですが・・・

引用:

イベントログ出力をさせ処理順番を確認したところ、
イベントログ出力1が3回出力されたあとに
イベントログ出力2が3回されています。


いつどのタイミングでスレッドが動作するかは、何も同期制御していない限りOS任せです。どちらが先に動くかは運しだいでしょう。

引用:

この処理順では3回ともiの最後の値を用いて動くことになってしまいます。


うそだ〜コードを見る限り1,2,3となるはずだ。

それはおいといて、スレッドの処理完了をまって次のスレッドを起動する必要がある(とすると何のためにスレッドにしているのか判らないけど)なら、毎回起動したスレッドの終了を待って次の処理に進む必要があるでしょうね。

#ところで、そのコードはC++だとエラーになりません?
#引数の型があっていないからキャストしないと
#コンパイル通らないと思うんだけど。

[ メッセージ編集済み 編集者: 甕星 編集日時 2005-03-11 22:35 ]
もぐ
会議室デビュー日: 2002/12/06
投稿数: 13
投稿日時: 2005-03-11 23:33
コードはまだ良く見ていないのですが、
普通、生のapiのCreateThreadは使わないのでは。
_beginthreadexか、MFCであればCWinThreadを使わないと、
Thread内でまともな処理はできないと思われます。

それともランタイムをまったく利用しない様なツールを書いていますか?
りう。
会議室デビュー日: 2005/02/24
投稿数: 6
投稿日時: 2005-03-14 01:57
こんばんわ。
りう。@日曜なのに別件作業で会社にお泊り です。
甕星様、もぐ様レスありがとうございます。

>甕星様(なんとお読みすればよろしいのでしょうか?)
引用:
--------------------------------------------------------------------------------
うそだ〜コードを見る限り1,2,3となるはずだ。
--------------------------------------------------------------------------------
はい。うそでした。
私の思い込みにより勘違いでした。
甕星様のレスを見てもう一度、調べなおしましたところ、
もともとのCreateThreadで渡す引数の編集にバグがあったため
スレッド起動時に最後の値を使って起動してるように
見えていただけでした。
単なる私の確認不足です。
味噌汁で顔洗って出直してきます(汗)

引用:
--------------------------------------------------------------------------------
#ところで、そのコードはC++だとエラーになりません?
#引数の型があっていないからキャストしないと
#コンパイル通らないと思うんだけど。
--------------------------------------------------------------------------------
これもおっしゃるとおりですね。
引数にint iを使っていますが、これはキャストしないと
コンパイルが通らないですね(滝汗)

実際はfor文の中身でパイプサーバーの起動、起動されたパイプサーバーの
監視するスレッドの起動を行っているのですが、全部書くと
えらい量になってしまうので掲示板書き込み用に簡略化するために
ソースを書き換えたのですが、ポカミスです。
失礼しました。

>もぐ様
引用:
--------------------------------------------------------------------------------
普通、生のapiのCreateThreadは使わないのでは。
_beginthreadexか、MFCであればCWinThreadを使わないと、
Thread内でまともな処理はできないと思われます。
--------------------------------------------------------------------------------
少なくとも現行システムで問題なく稼動しているのでThread内の処理は
まともに処理できていると思われます。

引用:
--------------------------------------------------------------------------------
それともランタイムをまったく利用しない様なツールを書いていますか?
--------------------------------------------------------------------------------
すいません。
勉強不足でランタイムを利用するコードとそうでないコードの差がすぐには
わかりません。調べてみます。
もぐ
会議室デビュー日: 2002/12/06
投稿数: 13
投稿日時: 2005-03-14 23:16
VCのラインタイムライブラリ(C/C++言語の標準関数)の関数には、
スレッドローカルな状態を保持する必要がある関数があります。
ちょっと思いつくだけでもtime関連やfcvt、rand、strtok等。

また、明示的に利用しなくても、他の標準関数が内部で利用していたり、
C++のクラスの実装に利用されている場合、またC言語が生成するコード
内にも、スタックオーバーフローチェック等、知らない箇所で
スレッドローカルな状態を必要とする処理があるかもしれません。

ですから標準関数を利用する場合はCreateThreadではなく
_beginthreadexを利用する事によって、スレッドローカルなデータの
確保と、ユーザのスレッド関数実行前にスレッド毎のスタートアップ処理が
実行された後にユーザのスレッド関数がコールされるようにします。

よほどVCのランタイムの内部処理やスレッド内で利用している全ての
関数やクラスの実装を詳しく知らないと、
怖くて生APIのCreateThreadは使用できないと思うのですが、どうでしょうか?
りう。
会議室デビュー日: 2005/02/24
投稿数: 6
投稿日時: 2005-03-15 14:52
>もぐ様

ご教授ありがとうございます。

引用:
--------------------------------------------------------------------------------
よほどVCのランタイムの内部処理やスレッド内で利用している全ての
関数やクラスの実装を詳しく知らないと、
怖くて生APIのCreateThreadは使用できないと思うのですが、どうでしょうか?
--------------------------------------------------------------------------------
生APIのCreateThreadの利用はそれほどむずかしいものなのですね。
勉強不足でした。

元々はMirosftのページから拾ってきたソースを元に開発したとのことで、
ここのソースではCreateThreadを使っています。
実際のスレッド側のソースはここに書いてある処理にPostMessage()を追加した程度で、
あとはほとんどそのままなので問題ないと思います。

しかし、当初の開発者が「VCのランタイムの内部処理や
スレッド内で利用している全ての 関数やクラスの実装」
を熟知していたわけでは無い様なのでたまたま上手くいったのでしょう。
今回のご指摘肝に銘じておきます。

ありがとうございました。
りう。
会議室デビュー日: 2005/02/24
投稿数: 6
投稿日時: 2005-03-15 14:53
すいません。追記です。
参考リンクを記載するのを忘れました。(汗)

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/ipc/base/multithreaded_pipe_server.asp
1

スキルアップ/キャリアアップ(JOB@IT)