マルチスレッドプログラミング相談室 その6at TECH
マルチスレッドプログラミング相談室 その6 - 暇つぶし2ch739:デフォルトの名無しさん
08/05/25 11:47:42
c/c++のvolatileはいろいろあるから、
ちゃんとmutexなどの同期オブジェクトを使うことをすすめる。
ただwindows限定ならvolatileにメモリバリアの意味があるのだっけ?

740:デフォルトの名無しさん
08/05/25 13:03:14
> c/c++のvolatileはいろいろあるから、
> ちゃんとmutexなどの同期オブジェクトを使うことをすすめる。

もしかして volatile 変数で同期とろうとか思ってる?

741:デフォルトの名無しさん
08/05/25 13:08:25
荒れる予感

742:デフォルトの名無しさん
08/05/25 13:10:20
>>739
メモリバリアの意味はない。
ただ、IA32はコヒーレントキャッシュだから、volatileだけでも
大して問題がないだけ。

743:デフォルトの名無しさん
08/05/25 13:18:53
ていうかこのケースは知らないが

もし「ループを一周余分に回すことになっても問題ない」という
厳密な同期が必要ないものならば、volatileで済むケースはある。
そんなに多くは無いが。

744:デフォルトの名無しさん
08/05/25 13:34:51
>もし「ループを一周余分に回すことになっても問題ない」という
>厳密な同期が必要ないものならば、volatileで済むケースはある。

むしろ今回のケースでは一周分余分に回すのがアウトという状況が考えにくい。


745:デフォルトの名無しさん
08/05/25 14:46:29
一周分余分に回ってアウトなら最初から排他なりセマフォなり入れるしな

746:719
08/05/25 16:06:04
結局↓のようなクラスにしました。今のところ問題ありません。

class Thread {
 HANDLE hthread_, hevent_; unsigned int id_; bool cancel_;
 void run(void) { while (1) { /* 具体的な処理 */ if (cancel_check()) { return; } } }
public:
 Thread(void) : hevent_(CreateEvent(NULL, TRUE, TRUE, NULL)), cancel_(false) {}
 ~Thread() { CloseHandle(hevent_); }
 void start(void) { hthread_ = (HANDLE)_beginthreadex(NULL, 0, Thread::entrypoint, this, 0, &id_); }
 void cancel(void) { cancel_ = true; SetEvent(hevent_); }
 void suspend(void) { ResetEvent(hevent_); }
 void resume(void) { SetEvent(hevent_); }
 bool cancel_check(void) {
  if (cancel_) { cancel_ = false; return true; }
  WaitForSingleObject(hevent_, INFINITE); return false;
 }
 static unsigned int WINAPI entrypoint(void* instance) {
  thread_t* p = static_cast<thread_t*>(instance);
  p->run(); CloseHandle(p->hthread_); p->hthread_ = 0;
  return 0;
 }
};


747:デフォルトの名無しさん
08/05/25 16:37:42
run()内で例外投げられたらまずくね

748:デフォルトの名無しさん
08/05/26 03:02:25
>>742
ダウト

749:デフォルトの名無しさん
08/05/26 03:25:49
kwsk

750:デフォルトの名無しさん
08/05/26 03:27:13
OoOの問題じゃないかなと思ったり。

751:デフォルトの名無しさん
08/05/26 13:30:52
UOがどうしたって?

752:匿名
08/05/30 15:12:16
スレッドは非常に難しいです。
スレッドを利用しないでコンカレントプログラムが容易にできます。
以下のページが参考になります。

URLリンク(www.cspjapan.org)





753:デフォルトの名無しさん
08/05/30 15:57:17
ばか?

754:デフォルトの名無しさん
08/06/05 15:10:05
生成したスレッドがmallocをしている最中に
SuspendThreadするとどんな問題が発生しますか?

755:デフォルトの名無しさん
08/06/05 15:26:07
mallocの中で排他制御しているだろうから、他のスレッドがmallocを呼
ぶと返ってこなくなるかも。



756:デフォルトの名無しさん
08/06/05 15:27:38
mallocがマルチスレッド対応版だと仮定すると、
ヒープ管理データへのアクセスの排他のために
mutexを握るタイミングがあるはず

そのタイミングでSuspendされると
ほかのスレッドがmalloc/free関連の処理をしようとして
mutex握れなくてずっと待ちに入る
newがmallocをベースにしているならnew/deleteも

はたから見るとハングアップに見える

757:デフォルトの名無しさん
08/06/05 22:23:21
>739
C#のvolatileはメモリバリアの意味もあるよ。
C/C++じゃないよ。

758:デフォルトの名無しさん
08/06/05 22:32:43
ふ~ん

759:デフォルトの名無しさん
08/06/07 21:41:57
MSDNのSystem.Threading.Thread.MemoryBarrierの説明が微妙でわかりづらい

>MemoryBarrier は、複数の Intel Itanium プロセッサを使用しているシステムなど、
>ウィーク メモリ オーダリングを採用したマルチプロセッサ システムでだけ使用します。



760:デフォルトの名無しさん
08/06/07 23:24:59
memory orderingの知識がないだけじゃね?
strong memory orderingのx86では不要。
シングルプロセッサ(1コア)のシステムでも不要。
weak memory orderingのItaniumを複数使ったシステムでは必要。
書いてあるとおりw
memory orderingはこれでも読んどけ
URLリンク(www.arch.ce.hiroshima-cu.ac.jp)
x86はSPARCのTSOと、ItniumはSPARCのRMOと同じはず

761:デフォルトの名無しさん
08/06/08 00:21:36
質問しようと思ったら>>746に俺が・・・
この場合だとentrypoint内でCloseHandleしてreturn完了後にendthreadex呼ばれるという
挙動であってるのかな?で、ハンドルも問題なく閉じられるのか?

762:デフォルトの名無しさん
08/06/08 05:09:09
>>746は無茶苦茶だろ。
とりあえず思ったこと。
 ・startで生成したhthreadを別のスレッドでcloseするのが変。
  代入前にサブスレッドが終了したらアウチ
 ・startが2回呼び出されたときのガードは当然してるよな
 ・とりあえずcancel_はvolatileにしとけ。即座でなくても
  そのうちtrueが伝わるだろう
 ・cancelは変数で一時停止がEventだが、どちらかに統一しとけ
 ・entrypointはprivateにしとけ
 ・entrypintでrunの例外処理しないとendthreadexが呼ばれない
 ・キャストはreinterpret_cast使え
 ・サブスレッドの実行を管理するThreadとサブスレッド処理のクラスを
  どうして同じにするかな。runとcancel_checkはThreadと別クラスに分離した
  方がよいと思う
 ・_beginthreadexとCreateEventのエラーチェックしろ
 ・サブスレッドが完了したか調べる関数がほしい
あと、Threadがスコープから抜けるとrunのthisが無効になる設計は嫌いだ。
Threadのデストラクタでjoin(WaitForSingleObject(hthread_))すべきだと思う。
呼び出し側が責任を持って事前にcancelを呼び出し、それを怠ったら
不正メモリアクセスでなく永久waitになった方がマシ

763:デフォルトの名無しさん
08/06/08 12:08:58
761ですが・・・俺の場合は
・コンストラクタで生成してるけどサスペンドで作成してるから、代入前に終了はないはず
・bool使ってやってます。全体的にこれらの操作はミューテックスで排他してるんですが、
 それで十分なんでしょうか?


・なってます
・なるほどやりました。
・なるほどやりました。
・実行管理がThreadクラスで、サブ処理がRunnableインタフェースを被ったクラスのrun()メソッド
 です。Thread自身もRunnableインタフェースを継承してます。(ただしrun()は空)
・失敗してたら何もしないようにしただけです・・・
・void Thread::join(DWORD timeout){
    if(tb == NULL)return;
    ::WaitForSingleObject(tb->hThread,timeout);
  } これで十分でしょうか?




764:デフォルトの名無しさん
08/06/08 13:05:59
MSが言っている"アラート可能な待機状態"とはどういう状態のことですか?

765:デフォルトの名無しさん
08/06/08 13:08:55
何らかのイベント?とかで待機を中断できるってことじゃね?

766:デフォルトの名無しさん
08/06/08 13:11:25
746みたいな事をやるときのboost::threadの楽さと言ったら…。

767:デフォルトの名無しさん
08/06/08 13:12:39
それは、普通の待機状態とアラート可能な待機状態の違いは
スレッドプロセスが__cdeclか__stdcallかの違いである
ということですか?

768:デフォルトの名無しさん
08/06/08 13:24:31
違いますね。APCとか理解できません。

769:デフォルトの名無しさん
08/06/08 13:55:21
>>764
重複I/Oを使うときにのイベント待機に使う。

770:デフォルトの名無しさん
08/06/08 19:17:36
>764
SleepExとかWaitFor~Exで、bAlertable=TRUEの状態で寝てるとき

771:762です
08/06/09 00:32:13
>>763
> ・コンストラクタで生成してるけどサスペンドで作成
 → 論理的に正しく動くのはわかったけど、わかりづらくない?
   ハンドル作成したスレッドが(デストラクタあたりで)closeするのが自然だと思うんだが。

> ・bool使ってやってます。全体的にこれらの操作はミューテックスで排他してるんですが、
 → startの多重チェックに同期は要らない。なぜならstartは
   一つのスレッド(メイン)からしか呼び出さないのが前提だから

> Thread自身もRunnableインタフェースを継承してます
それはJava APIと同じ設計だけど、APIの設計ミスだと思う。
各クラスの役割は最低限にしようよ。
 Runnable: サブスレッドで実行する処理のクラス(主にサブスレッドで使用)
 Thread: Runnableのスレッド実行を管理するクラス(メインスレッドから使用)
実行制御でもcancel/suspend/resumeは処理固有なのでRunnable側に実装。
スレッドハンドルはスレッド実行管理の話だからThreadでclose。

> void Thread::join(DWORD timeout)
できれば戻り値をboolにして
DWORD status = ::WaitForSingleObject(?????)
if (status == WAIT_ABANDONED) throw ????;
return status == WAIT_OBJECT_0; // 完了したかどうか
かな。

772:デフォルトの名無しさん
08/06/09 02:04:45
JavaのThreadにケチつけるアホがいるスレはここですか?

773:デフォルトの名無しさん
08/06/09 02:17:36
JavaのThread implements Runnableは失敗だろjk

774:デフォルトの名無しさん
08/06/09 18:16:32
Treadクラスの継承が失敗だろ

775:デフォルトの名無しさん
08/06/09 23:04:19
761です。もう全然うまくいかないので、なんか言ってもらうために
スレッド周辺のプログラムをアップしてみます・・・。include "common.h"は消していいです
お願いします><
URLリンク(ccfa.info)

776:デフォルトの名無しさん
08/06/09 23:06:31
よし、何か言ってやる。
>>775 がんばれ!

777:デフォルトの名無しさん
08/06/10 01:28:22
>>775
○Mutex
・LockでWaitForSingleObjectの戻り値確認しろ。タイムアウトしたら大変なことになるぞ
○Thread
・何でthread_bodyの定義を書く前に変数宣言できるんだ?コンパイル通った?
 thread_bodyのスマートポインタでないとマズくね?
・start内に例外発生するとマズい場所が多すぎ。line 60,61,62,63,64,68
・isAliveのロジックが間違ってる。スレッドがSTILL_ACTIVE返したら区別つかない。
 WaitForSingleObject(スレッドハンドル) == WAIT_OBJECT_0 で判断しろ
・ThreadProcで(const Thread&)のキャストは要らないでしょ
・マップ操作前後のロックタイミングはこれでいいと思う
・suspend/resumeのロックはこれでいいと思う
・joinでWaitForSingleObjectの戻り値確認して
・isAliveにロックは不要
・クラス設計が変。currentThreadの返したThreadは何だ?
 実際のrunと関係ないrunを持つThreadをnewして返すのは絶対変だ
・Runnableとt_threadの使い分けをもう少し整理して
・ヘッダ名見直せ。<cstdio><windows.h><process.h><map><cstdio><sstream>

> tb=thread_pool_for_runnable[target];//既にあるRunnableの時はそれを使う
? エラー返すべきでは?

あと、ミューテックスのロックはヘルパークラス作れ。
コンストラクタでミューテックスを受け取ってロックし、デストラクタでアンロック。
でないと途中で例外が発生したときにいちいち対処できない。

> もう全然うまくいかないので
何がうまくいかない? 何となく動きそうだが。
コンパイルエラーとか言ったら殺

778:デフォルトの名無しさん
08/06/10 07:15:40
今携帯なんで、後で詳しく見ますが、うまくいかないというのは
これで画像読み込みをしたときに画像読み込みが出来なかったりするんです
実験中には終了時に不正アクセスみたいのが出たり…

779:デフォルトの名無しさん
08/06/10 14:38:51
777が優しすぎる
俺が男なら惚れてたね

780:デフォルトの名無しさん
08/06/10 14:56:56
俺は男だから惚れた

781:デフォルトの名無しさん
08/06/10 16:38:37
じゃあ掘れるのか

782:デフォルトの名無しさん
08/06/10 19:43:21
惚れたけど掘れない。

783:719
08/06/10 20:22:05
いやぁ、勉強になるなぁ…。


784:デフォルトの名無しさん
08/06/11 07:10:26
質問があります
pthreadでは途中でスレッドをキャンセルする場合
pthread_cancelを遅延キャンセルでコールして、
クリーンナップハンドラでリソースを開放するという方法が考えられますが、
C++では実行環境(gcc,glibc)によって、クリーンナップ内でオブジェクトの
デストラクタが呼ばれなかったり、例外処理が行われないなどといったことがあるみたいですが、

「C++ではこのようにしてpthreadを中段させるべき」といった
定石的手法が確立しているのでしょうか?

できればURIなど情報源などもあれば教えてください。

【OS】
Linux2.6
【言語】
C++
【実行環境】
RHEL5(pthread)
【その他突起する事項】
「RHEL5の中のライブラリならサポートしてるので気にするな」ってのは無しで

785:デフォルトの名無しさん
08/06/11 07:47:54
外から中断なんかしない。
当たり前すぎて泣けてくる。

786:デフォルトの名無しさん
08/06/11 12:24:11
>>784
安全に中断させる方法なんて存在しない。

だが、スレッドのエントリ関数のreturnを実行して正しく終了させる方法はいくらでもある。

787:デフォルトの名無しさん
08/06/11 13:55:11
> 「C++ではこのようにしてpthreadを中段させるべき」といった
> 定石的手法が確立しているのでしょうか?
中断通知機構は自分で独自に実装。必ずエントリポイントの関数まで
戻るようにする。
異常時に終了するため、終了用の例外クラスを作成。エントリポイントのみ
でcatchし、他はクラスに対し例外中立なコードを書く。
ソースは俺。

788:デフォルトの名無しさん
08/06/11 14:04:26
>>778
joinせずに終了したか、Thread,Runnableのメモリが誤って解放されたのでは

789:デフォルトの名無しさん
08/06/11 20:40:04
スレッド止めてプロセスにする

790:777
08/06/11 21:51:22
>>775
GetLastErrorの戻り値判定ロジックが逆。
細かい間違いは修正したが普通に動いた。元のろだ?のup方法がわからなかったので↓にup
URLリンク(www11.axfc.net)
DLパスは mt

さすがにmy_ptrとかいうのはboost::shared_ptrに置き換えさせてもらった。

791:デフォルトの名無しさん
08/06/11 22:28:58
アクターモデルって奴の
C++とかjavaとかでのサンプルない?

792:デフォルトの名無しさん
08/06/11 22:36:55
761です
>>790
ブワッ!なんと言うやさしさ・・・やっと時間が取れたので、777を元に修正してたら、なんという
でも俺はウホじゃないです。すいません

(const Thread&)のキャストですが、こうしたらローカル変数の寿命がどうたらで1個分生成・破棄の
コストが浮くかなあと思って付けたんですが・・・まぁ、確認もせずにつけたので効果はいざ知れず

> currentThreadの返したThreadは何だ?
この関数を実行したスレッドがスレッドプール内に存在すれば、そのスレッドを操作する
Threadオブジェクトを返します。
既存のRunnableの時再利用するのは
Hoge(){
Thread th(this);th.start();
}
~Hoge(){
Thread(this).join();
}
とすることに憧れていたからです・・・。つまり俺がちょっとおかしいのです

793:デフォルトの名無しさん
08/06/11 23:27:08
pthread mutexで

読みスレッドが2人
書きスレッドが2人

といる場合、rwlock使うと読んでる間に
書き込もうとしてもロックされる?




794:デフォルトの名無しさん
08/06/12 00:24:12
pthreadは知らないけど一般のReader-Writer-Lockなら排他制御されなぎまずいんじゃね。
Readerのみの場合に排他されないんだと思う。
 Reader vs. Reader → 排他されない
 Reader vs. Writer → 排他される
 Writer vs. Writer → 排他される

795:デフォルトの名無しさん
08/06/12 00:38:59
Pthreadもそうだったと思う
Man読みゃいいんだけどね

796:デフォルトの名無しさん
08/06/12 01:47:42
スレッドAがrdlockする
スレッドBがwrlockしようとする(が、rdlock中なのでブロック)

この状態の時に、スレッドCがrdlockしようとすると
1.スレッドCがrdlockを取得(Aと共存)出来る
2.スレッドB(ロック獲得優先権がある)の処理終了までブロックする
一般的にはどうなる?

・一般的に、rwlockと呼ばれるものの動作として決まっている(どっち?)
・pthreadの標準として決まっている(どっち?)
・何も決まってない(実装依存)

797:デフォルトの名無しさん
08/06/12 01:54:39
>>796
URLリンク(opengroup.org)
> It is unspecified whether the calling thread acquires the lock
> when a writer does not hold the lock and there are writers waiting for the lock.

何も決まってないぽい

798:デフォルトの名無しさん
08/06/12 02:00:50
おー、thx


最新レス表示
レスジャンプ
類似スレ一覧
スレッドの検索
話題のニュース
おまかせリスト
オプション
しおりを挟む
スレッドに書込
スレッドの一覧
暇つぶし2ch