トップページ⇒tech
986コメント340KB

マルチスレッドプログラミング相談室

■ このスレッドは過去ログ倉庫に格納されています
0001デフォルトの名無しさんNGNG
マルチスレッドプログラミング相談室
0153デフォルトの名無しさんNGNG
forkとスレッドって代替するものなの?
forkはもういらないって事?
0154デフォルトの名無しさんNGNG
>>153
んなこたぁない
forkの方が便利な場合も依然としてある
0155デフォルトの名無しさんNGNG
>>151
まずはスレッドを使わないでちゃんと受信ができているかテスト。
0156デフォルトの名無しさんNGNG
>>152
どう考えてもマルチスレッドの質問じゃないと思われ。
0157デフォルトの名無しさんNGNG
>>153
モジュール間の結合度が低くてデータのやりとりがIPCで十分な場合、
forkを使う方がいいと思ってる。
0158デフォルトの名無しさんNGNG
メモリ空間を共有するならスレッド。
0159デフォルトの名無しさんNGNG
>>152
分かってないなあ。
正確さをあきらめるならタイトループを
ベンチマーク的に測定してテキトーに。
たぶんきれいな方形波でなく、
不揃いのパルスになる。

正しくパルスを送るんなら、そのデジタルI/Oボードに
そのパルスを発生させるICを何とかして繋ぐのが正攻法。
H8なんかはPWMとRS232を内蔵していて便利。
0160名無しさん@お腹いっぱい。NGNG
ちょっと古い話ですみません(>>18のWin32のロックについて)。

>InterlockedIncrement()はなんでガードしないと行けないんですか?

マルチプロセッサ環境で問題が出ます。
inc命令といってもリード/ライトサイクルがあり、その間に他のCPUが処
理する可能性があります。実際、マルチプロセッサマシンでそんな不具合
が起きそうなプログラムを書いて試してみてください。

非x86のときは、x86の命令に対応するものに展開される保障はありません
(>20も少し触れている)。
0161デフォルトの名無しさんNGNG
>>157
やっぱマルチプロセスもいいよね。プロセスの死亡は痛くないけどスレッドの死は
痛い。あと信頼度の低いものをまとめあげるときには、疎な結合のほうが
いいから、プロセスを防波堤として使うのも好き。

にしてもマルチプロセスのときのプロセス間の連絡って皆どうしてんの?
POSIX IPC? System V IPC? pipe? socket?

それともRPC? またはCORBAとか分散オブジェクト使うの?
0162デフォルトの名無しさんNGNG
>>161
とりあえずsocket。
0163152NGNG
>156
言葉足らずでしたか。スマソ
ステッピングモータを回すスレッド以外に、通信や表示のスレッドがあって、
モータを回す際にスリープを正確にさせたい。
0164デフォルトの名無しさんNGNG
>>163
159みれ >>159
0165152NGNG
>>164
みたけどー。
要はmsec未満のスリープはできないのね。
0166デフォルトの名無しさんNGNG
>>152
そこまでの解像度を持つタイマが必要なら
もはやNTの出る幕ではないのでは…?
リアルタイムOSとか必要なんでは? よく知らんけど。
0167デフォルトの名無しさんNGNG
[参考]マイクロ秒単位の話:
以前NT用のセントロボードの読み出しドライバーで、
割り込みの奴とストローブをCPUで監視する奴の2種類
付属している奴があった。
その注意書きに、割り込みなしの奴は取りこぼしあり
とあり、保証なしだが、全く使えないわけではなく、
テキトーもありなんだとちょっと感心した。
0168デフォルトの名無しさんNGNG
マルチメディア系のライブラリなら、
マイクロ秒単位でタイマーの監視は出来そう
でも、それをやるとCPUがそれにかかりきりで、
ほかのスレッドを動かせなかったりするんでは。
0169デフォルトの名無しさんNGNG
>>166
だから>>159見ろと何度も言われてるのに取り合わない馬鹿は
ほっといて勝手に困らせとけ。
0170デフォルトの名無しさんNGNG
>>169
165に見たと書いてるけど。。
0171デフォルトの名無しさんNGNG
>169
ただのヴァカ
0172デフォルトの名無しさんNGNG
いにしゃらいずくりちかるせくしょん
0173かなみNGNG
複数のスレッドから同じ関数を呼び出しちゃマズイですか?
関数内ではstaticな変数は使っていないんですが、、、
0174デフォルトの名無しさんNGNG
基本的にはなんら問題ない。競合問題というのはデータに対して起きるもので、
コードに対して起きるものではないから。
実は同じオブジェクトを引数に渡してて、そいつが競合してるとか?
0175かなみNGNG
ありがとうございます。
大丈夫なんですね。
0176名無しさん@XEmacsNGNG
>>173
> 関数内ではstaticな変数は使っていないんですが、、、

MT(multi-thread) safeな関数しか呼び出しちゃ駄目よーん。
例えば、UNIXだとgethostbynameはMT-safeじゃない。
gethostbyname_rがMT-safe版。
0177デフォルトの名無しさんNGNG
>>176
呼び出す周囲をMutexでくるむという手もある
すべての箇所で出来るという保証があればの話だが
0178デフォルトの名無しさんNGNG
>>173
別にマズくないです。
同じメモリ領域に、複数のスレッドで同時に書き込んだり、
あるスレッドから書き込むと同時に別スレッドで読み込んだり、
しない限り全然大丈夫です。
0179かなみNGNG
「同時に同じ領域へアクセスしなければ特に排他処理をしなくても問題ない」
と理解しましたが、それでOKですか?
0180デフォルトの名無しさんNGNG
>>176
たまに表示が化けたり原因不明のエラーを出すの得意だろ
0181デフォルトの名無しさんNGNG
>>179
同時に読み出しだけならOKです。
書き込みが混じるときは気を付けましょう。
0182デフォルトの名無しさんNGNG
>>177
ラッパー関数かけ。
0183デフォルトの名無しさんNGNG
便乗で質問させてください。
時刻の取得⇒文字列として表示、にlocaltime, ctimeを使おうと思ったのですが
スレッド安全ではないために、localtime_r, ctime_rで記述しました。

ところがコンパイルは通るものの、実行すると上記箇所にて
coreを吐いて死んでしまいます。
(localtime, ctimeで記述時の動作は、期待通りです)

Solaris8, gcc295を使用しているのですが、
"*_r"関数には、何かしらの制限等があるのでしょうか?
0184デフォルトの名無しさんNGNG
取得から表示(もしくは中身のコピー)をするまで、クリティカルセクションで挟んどけ。
mutexでもいいぞ。
0185デフォルトの名無しさんNGNG
>>183は単にメモリを確保してないと思われ。
0186デフォルトの名無しさんNGNG
萎えるな、それ。
0187デフォルトの名無しさんNGNG
>>183
とりあえず「スレッドセーフ」って読んだほうが良いかと...。
>>179
どういう構造でmulti-threadが実装されているのか理解するまでは
愚直に危うそうな資源を排他するのをおすすめします。
「同時に同じ領域へアクセスしなければ特に排他処理をしなくても問題ない」
という表現に危うさを感じます。
たとえば、排他をしないでどうやって同時でないことを保証しましょう?
0188名無しさん@XEmacsNGNG
>>179
マルチスレッドセーフって概念も理解したかどうか不安。

>>180 何でしょ?なにか用ですか?
0189デフォルトの名無しさんNGNG
localtimeもctimeもスレッドセーフだと思うのは俺の気のせいか?
0190デフォルトの名無しさんNGNG
*_rは、結果文字列バッファを引数で渡すので、ちゃんと確保してればスレセーフ。

フツーのlocaltimeとかctimeとかは、ライブラリ内部の?共通バッファに
結果を展開するので、別のスレで使われると、書き換えられる可能性がある。
ということじゃなかったかな?

まあ、あんまりセーフかどうかを気にしなくてもいいのかもしれんが、建前上はスレセーフではない。
0191_NGNG
VCだと*_rがないけど、マルチスレッドライブラリのリンクで
保障されるのかな
0192183NGNG
皆様のご指摘どおり、メモリを確保していないために
起きた現象でした。

メモリ確保をすることによって無事解決をしました。
ありがとうございます。

メモリを確保する必要があるのですね、知りませんでした。
その必要性は、以下のような解釈でよろしいですよね。。。

localtimeは、関数内static領域を保持することを前提に設計された関数であり
localtime_rは代替関数である。この関数はライブラリ内部の共通バッファを
使用しないことによってスレッドセーフを実現しているため、当然
自前でメモリを確保する必要性がある。
0193デフォルトの名無しさんNGNG
>>191
VC++の場合、マルチスレッド用のランタイムは内部で
動的なバッファを確保してる。
0194デフォルトの名無しさんNGNG
VCはランタイムライブラリの持つグローバル変数は全部TLS(スレッドローカル領域)
なので、大丈夫だよ。>>191
0195デフォルトの名無しさんNGNG
全部じゃないだろ。そんなことしたら排他制御もできん。
0196デフォルトの名無しさんNGNG
排他制御はOSの機能でやってるんでしょ
ま、「全部」ではないと思うが
0197デフォルトの名無しさんNGNG
質問よろしいでしょうか?
常駐処理をスレッドで作成しています。
スレッドが終わった場合に、もう一度起動するように
しようとしているのですが、
終わった筈のスレッドなのにGetExitCodeThreadでのコードが
STILL_ACTIVEになってしまいます。
何かおかしいでしょうか?コードは次のようなものです。
よろしくお願いします。

void main()
{
  〜略〜
 while(1)
  GetExitCodeThread( (HANDLE)hThread, &ExitCode );
  if( ExitCode != STILL_ACTIVE ){
    hThread=_beginthread( ThreadProc, 0, (VOID *)NULL);
  }
 }
}

void ThreadProc( void *p )
{
  /*処理*/
  return;
}
0198デフォルトの名無しさんNGNG
mainもThreadProcも戻り値必須だボケ
0199194NGNG
>>195 全部ってのは言いすぎでしたん。スマソ
0200デフォルトの名無しさんNGNG
てか、ちゃんとスレッドプロシージャの型を見ような。
cdeclとstdcallとではスタックの解放の仕方が違うんだよ。
大方、リターン直後でスタック破壊を起こしていると思われ。
0201デフォルトの名無しさんNGNG
>>192=183
ちょっと話題がずれるけど、ポインターをやりとりする時に
実態の領域を誰が用意するかはドキュメントを読まないと
判らないのはC言語の限界ですよね。。。
用意するにしても、領域の大きさも表現できないし。
>localtime_rは代替関数である。
代替かなぁ?
localtimeの仕様が気に入らない人が多くって、
thread-safeにするついでに関数の定義を直しちゃったとか?
0202デフォルトの名無しさんNGNG
>>201
sprintf→snprintfという変化もあるよ
thread-safeとはまた別に。
0203名無しさん@XEmacsNGNG
>>201
> thread-safeにするついでに関数の定義を直しちゃったとか?

1. 仕様を変えないとMT-safeにならない。
2. 勝手にmallocするようにしないとMT-safeにならない。

という究極の選択で、1を選んだという事。
Lisp, Java, C#が2を選んで、

> 実態の領域を誰が用意するかはドキュメントを読まないと
> 判らないのはC言語の限界ですよね。。。

を克服するためにGCを採用した(知る必要なし)のはご存知の通り。
0204デフォルトの名無しさんNGNG
>>194-196
thread safeじゃない物はstruct _tiddataでまとめてTLS管理してる
ようだが。crt/src/mtdll.h辺り参照。
0205デフォルトの名無しさんNGNG
Windows&VC++環境で親スレッドから子スレッドを終了したいのですが、
どうしたらいいので良いでしょうか?
自分で調べた中では、自分自身(呼び出し元)を終了させる方法しか
見つかりませんでした。
0206デフォルトの名無しさんNGNG
誰かが(親でも子でも、別EXEでも)社内掲示板(同期オブジェクト)を使って、リストラの通知をする
↓
仕事しながらたまに社内掲示板を待ち時間ゼロとかで調べる
↓
終了通知が来てたら、仕事を辞めて首をつる
↓
スレッドハンドルとかを待機して解雇を確認する
スレッドハンドルで解雇の確認ができないときは、死に際に
遺書(同期オブジェクト)を残す
↓
解雇完了
0207デフォルトの名無しさんNGNG
TerminateThread
0208デフォルトの名無しさんNGNG
だせーよおまえ
0209デフォルトの名無しさんNGNG
>>207
どうもです。
TerminateThreadについては、参考書に例として載っていましたが、
リスキーなので使わない方が良いと書かれていました。
他に安全な方法は無いでしょうか?
0210デフォルトの名無しさんNGNG
>>206をよく見なさい
0211デフォルトの名無しさんNGNG
>>209
206の解説:子供スレッドはある変数を監視し、それがある値に
なったら終了するようにしておく。親スレッドは、終了させたく
なったら、その変数をセットする。

当然だけど、子供スレッドは定期的にその変数を監視しないといけない。
かなり面倒。通信量が少ないなら別プロセスのほうが楽かもね。

任意のタイミングで無理矢理殺せるスレッドライブラリは少数派。
つかSolaris以外に知らない。
0212デフォルトの名無しさんNGNG
>>211
>任意のタイミングで無理矢理殺せるスレッドライブラリは少数派。
ただのpthreadでは...。(普通のUNIXで採用しているthreadね(かなり略))
0213デフォルトの名無しさんNGNG
単純に終了のための変数参照でもいいし
メッセージループと同様の作りでもいい、こっちの方がメッセージ
遅れるので融通利く
0214デフォルトの名無しさんNGNG
みなさんinet_ntoa()ってどうしてます?
私は代替にスレッドセーフなやつを適当に
自作してつかっちゃってるんだけど・・
0215 NGNG
俺はinet_ntop()を使うようにしてる。ついでにv6対応にして(゚д゚)ウマー。
0216デフォルトの名無しさんNGNG
通信デバイスにアクセスすると、たまに「ERROR_OPERATION_ABORTED」という
エラーが返ってくるんですが、これってどんなことが起こってて、どう解決していけば
いいのでしょうか?

VC++なんか初めてなのにマルチスレッドのプログラムのデバッグやらなきゃ
いけなくてヘルプ見てももうさっぱりです。
他のスレッドが使っているのだろうか?などとも考えたのですがそれをどうやって
調べればいいのかもわからないです・・・

ホントどうしようもなくシロートで申し訳ないんですが、よろしくお願いします。
0217デフォルトの名無しさんNGNG
>>214
WindowsNT以降ではinet_ntoaはスレッドセーフ(同じスレッドで再度Winsock関数が呼び出されるまで返された文字列は有効)だ。strtokも同様。
0218デフォルトの名無しさんNGNG
>>212
そのpthreadはニセモノだね。
0219デフォルトの名無しさんNGNG
普通のunixで採用しているthreadって何?
0220デフォルトの名無しさんNGNG
>>211
解説どうもです。
>>213
やっぱり、皆さんの提案されるような小技をつかわないと実現できない
のでしょうか?
シンプルに命令一つで実現できないものかと調べています。
あっても良さそうな命令なんですが、やっぱ別スレッドを終了させると
言う事はあまり良くない事(いろいろと問題がある)なのでしょうか?
仕様上、今の所は別プロセスを作る事は考えていません。
0221名無しさん@XEmacsNGNG
>>220
> シンプルに命令一つで実現できないものかと調べています。

何作ってるか書かないと、
そのthreadが取得しているlockはどうするんだ?
とかいうアドバイスをしにくいぞ。
0222デフォルトの名無しさんNGNG
スタック以外何も占有していなければ、外部からTerminateしても問題なし。
そのスレッド内で使用するあらゆるリソースのためのマネージャを、メインスレッドが管理すればいい。
ただし、トランザクション中だけ、メインスレッドが待機する仕組みを必要とする。

で、そういうプログラムを以前1回仕事で作ってみたけど、問題なく動いてはいるね。
(子スレッドが使用するリソースがある程度限定できたからだけど。)
0223デフォルトの名無しさんNGNG
>>220
理解しやすいように具体例を挙げると、こういうことです。
次のようなスレッドがあるとします。

void thread()
{
 FILE* fp = fopen("a.txt", "r");
/*ここで色々な処理をする*/
fclose(fp);
}

メインスレッドからこのスレッドを終了させようとする場合、
このスレッドは、まだ処理実行の途中ですよね?
スレッドを途中で終了させたら、fclose は実行されないですよね?
困りませんか?

ここでfcloseが確実に実行されるためには、

(1) メインスレッドで fclose を実行する
(2) 子スレッドが自分で終了処理して fclose を実行する

のいずれかですが、FILE* fp がローカル変数だったら、
メインスレッドからファイルを閉じる方法は実行不可能です。

メインスレッドから子スレッド終了させると、
子スレッドは fclose を呼ぶヒマなく終了させられますからダメです。

そーすると、終了フラグを立てるなりして
子スレッドが自主的に終了するよう仕向けるしかないわけです。

おわかり?
0224デフォルトの名無しさんNGNG
>>222
但し書きのないいつ殺してもいいスレッドなんて
業務プログラムでは皆無だな(藁

ゲーム系ならあるのか?
0225デフォルトの名無しさんNGNG
>>220
残念ながら命令ひとつてポンってのはないよ。

スレッド管理をしてくれる魔法のつえなんてどこにもない。
ほとんどの場合同期処理が絡んでくるから、
設計は慎重に、コーディングは明快かつ丁寧にやるように。
0226212NGNG
>>218
>そのpthreadはニセモノだね。
(単語の認識に違いがあるかもしれませんが、)
pthread_kill()は意図した動作と違うのでしょうか?
0227デフォルトの名無しさんNGNG
pthread_kill()
send a signal to a thread

SYNOPSIS
#include <pthread.h>

int pthread_kill(pthread_t thread, int sig);

DESCRIPTION
The pthread_kill() function is used to request that a signal be delivered to the specified thread. As with kill(), if sig is zero, error checking is performed but no signal is actually sent.
0228212NGNG
>>227
マニュアルは私も引けるのですが、意図はいかがなものでしょう?
「任意のタイミングで無理矢理殺せるスレッドライブラリ」は
ニセモノ?ホンモノ?
0229デフォルトの名無しさんNGNG
227をどう読むと「無理矢理殺す」になるの?
0230デフォルトの名無しさんNGNG
>>228
pthread_killを使えばシグナルを遅れるが、
受け取り側のスレッドが正しくシグナルを処理できないと、
後で悲惨な目に遭うよ。
0231212NGNG
>>229(=227?,=218??違うかな?)
UNIXではSIGKILLを送ればシグナルのハンドルできずに終了です。
0232デフォルトの名無しさんNGNG
212がニセモノというオチだったのか
0233212NGNG
あう?
言われていることの意味がわからんです。
そろそろ眠いけど、教えてほしいです。
0234デフォルトの名無しさんNGNG
元質問者はWinのはずなのになぜpthreadの話になってる?
0235デフォルトの名無しさんNGNG
>>221-225
どうもありがとうございます。

> 何作ってるか書かないと、そのthreadが取得しているlockはどうするんだ?
> とかいうアドバイスをしにくいぞ。
はい、其の通りですね。情報が少なくてすみませんでした。

1つのプロセスがあり、親スレッドと子スレッドが常駐しています。
子スレッドでは通信処理(無限ループ処理で、イベント待機していて
イベントが発生すれば通信を行う)を行っています。

今、考えている流れは、
1)メインプロセスから、このプロセスに終了の依頼(アプリ終了処理依頼)
 ↓
2)親スレッドが子スレッドに終了依頼をかける
 ↓
3)子スレッド内の処理で通信中であっても通信を強制的に終わらせて
 子スレッドを正常に終了させる。(ローカル変数もろもろを全て開放)
 ※但し、通信中の内容については保証しなくても良い。
 ↓
4)親スレッドから子スレッドが正常に終了したのを確認した上で、親スレッドを終了。

要は、子スレッドにおいて通信処理を行っている最中に割り込みをかけて
子スレッドを終了したいと考えています。

<現在>
子スレッド(無限ループ)
・イベント待機
・・イベント発生⇒通信処理

<変更>
子スレッド(無限ループ)
・終了依頼チェック
・・終了依頼あり⇒子スレッド終了
・イベント待機
・・イベント発生⇒通信処理

上記のようにも考えてみたのですが、これだと終了依頼をかけても通信中の場合だと
通信が完了して、ループが先頭に戻ってくるまで終了できません。通信中であっても
すぐに子スレッドを終了させたいと考えています。(通信内容については保証しなくて
もいい)
以上、よろしくお願いします。
0236デフォルトの名無しさんNGNG
なんと言うかスレッドの問題じゃなくて非同期通信にしろってだけじゃないのか?
0237 NGNG
親スレッドで通信のイベント感知して、
スリープしておいた子スレッドを起こした方がよくない?
0238デフォルトの名無しさんNGNG
Windowsはよくしらんけど、もしpthreadなら上にでてるpthread_killでいいじゃん。
SIGALRMを送って、子スレッドの関数がEINTRで返ったのをみて
終了すればいいような…
0239デフォルトの名無しさんNGNG
>>235
窓だったら子スレッドをMsgWaitForMultipleObjects使わせて待機させ、
親スレッドは子スレッドにメッセージを投げることで終了依頼とする
通信を完全に非同期で行なえばメッセージを待つだけでも出来る

UNIXだったらパイプをポーリングすれば親の終了依頼とクライアントとの
通信を同時に待機できる

細かい使い方は自分で調べろ
0240デフォルトの名無しさんNGNG
>>239
>>235は強制的に終らせてなどと言ってるので通信は
ブロッキングでしたいのだと思われ。
0241デフォルトの名無しさんNGNG
>>224 うわ、頭の硬い奴。
0242デフォルトの名無しさんNGNG
他のスレッドに例外を発生させる方法って、あったっけ。
0243デフォルトの名無しさんNGNG
Javaなら。
スレッドを外から強制終了させよーとすると ThreadDeath 例外が走る。
0244デフォルトの名無しさんNGNG
すまん、舌足らずです。

Win32&C++で、あるスレッドから別のスレッドに例外出せたら、
ちょっと悦なんですが。
ざっと調べた範囲ではなさそうだったんだけど、
見落としてるかもしれんので。

なんか情報あったらください。
0245 NGNG
Sub Macro1()
Dim i As Double
Dim iAnswer As Double

X = Worksheets(1).Cells(13, 2)
A = Worksheets(1).Cells(11, 7)

For i = X To A Step 0.0000001

iAnswer = i

Next

sAnswer = Str(iAnswer)

Worksheets(1).Cells(13, 8) = sAnswer

End Sub
-----------------------------------------
X=C10
A=IF(A13="",""ROUND(B13+E13+F13,6))
と、それぞれのセルには数式が入っています。
Aのセルは
sAnswerのセル(13, 8) に数値が入らないとAの答えが出ないから
「#DIV/0!」となってます

この状態で実行すると
For i = X To A Step 0.0000001
のとこで「型が一致しません」とエラーなります。
「#DIV/0!」だとダメなんでしょうか?
0246デフォルトの名無しさんNGNG
たとえば、そのほかのスレッドで頻繁にアクセスされるインスタンスなどを
ゼロクリアしてしまえば、そのスレッドがそのポインタをさわった瞬間に
Access Violation例外が発生するようにできますが。

やはりメッセージを受け取って、例外を送出するという方が無難でありましょうか。
0247デフォルトの名無しさんNGNG
>>243
イキナリThreadDeathのはなしより、普通は
「WAITスレッドにInterruptかけてInterruptedException」
のはなしが先でしょうに。
0248デフォルトの名無しさんNGNG
>>242
共有メモリのフラグを時々見に行って、フラグが
落ちていたら例外投げればいいじゃん。
0249名無しさん@XEmacsNGNG
>>244
> ざっと調べた範囲ではなさそうだったんだけど、
> 見落としてるかもしれんので。

「Win32 マルチスレッド プログラミング」J. Beveridge, R. Wienerでは、
第五章「スレッドを制御する」に「何時間にもわたる調査の結果、
私は確信を持ってWin32 APIは別のスレッドに対して例外を送出するための
標準的な手段はサポートされてないと断言する事が出来る」だってさ。
// ここで言う「非標準の」はdebug APIで>>246など。

Compilerはかなり大変だよ、非同期に例外送出されると。
どの命令間でも例外が発生すると思って"exception safe"を維持するなんてさ。
けど、欲しい機能だけどね。pthreadのcancel pointみたいに限定局面でいいから。
0250242=244NGNG
むー、やはりそうか。情報ありがとうございます。>みなさま
0251デフォルトの名無しさんNGNG
マルチスレッドとsignalって共存可能かにゃ?
0252デフォルトの名無しさんNGNG
>>251
する。と思うけど。
■ このスレッドは過去ログ倉庫に格納されています