マルチスレッドプログ ..
205:195
07/02/27 14:54:42
>>203
キャッシュラインをまたぐ場合って、普通のコードじゃ起きないし、
char buf[sizeof(int)+1]; *(int *)(buf+1) = 0;した場合とかでしょ?
今では例外飛ばさずにアクセスできるアーキテクチャの方が少数派なのでは?
>>204
他の変数を確定的に見る必要がある場合はOoOの関係で無理。
>>195はひとつのintを扱う場合なつもりで書いてます。
>>196を例にすると、タイマでプログレスバーを更新する時はvolatileのみ、
最後に終了したかを確定的に判断したい時だけpthread_join()するケースとか。
206:デフォルトの名無しさん
07/02/27 15:21:57
>>205
PCで使われているCPUの98%は、それをごく普通に実行します。
任意位置からの32bitの整数読み出しはMPEG系のビデオコーデックの
処理では多利用されるし。
207:195
07/02/27 16:11:02
CPUの数が多いのは当たり前だからアーキテクチャって書いたのに。
そんな下らないツッコミは要らないって。。
Codecの処理だろうが、境界整列に反したメモリアクセスなんて
行儀の悪いコードなんじゃないの?少なくともポータブルじゃない。
処理系依存のレベルで言ったらvolatileの比じゃないと思うんだけど。
208:デフォルトの名無しさん
07/02/27 16:25:35
アーキテクチャの数で言って多いか少ないかについては、
漏れは何も言っていません。
実存するシステムの大半では割合で例外は飛ばないという
(関連する)別の事実を提示しただけですよ。
209:195
07/02/27 18:33:40
>>208
おまえ例外が飛ばないって書きたいだけだろ?
実際のとこはどうなのか、って話がしたいんだよ。
210:デフォルトの名無しさん
07/02/27 19:55:55
理屈で勝てそうにないと急におまえ呼ばわりですか。
実際の例で言うなら、MPEGのシステムストリームから4バイト長さの整数を取り出すとき、
ポータビリティを重視している ffmpeg ではバイト単位で取り出して整列してますし、
IA32/64が前提のIPPではポインタをそのままデリファレンスしてアライメントを気にせずに整数を取り出してます。
「普通のコードじゃ起きないし、例外飛ばさずにアクセスできるアーキテクチャの方が少数派」だから、
キャッシュラインまたぎの問題は無視してよいとでも言いたげな感じですが、
実際のとこどんなプログラムをどれだけ調べた上で書いてるんですか?
211:デフォルトの名無しさん
07/02/27 20:59:04
IA86において、そもそも、アラインメントが狂った位置への
アトミック書き込みはできない。
212:デフォルトの名無しさん
07/02/27 21:54:58
傍から見てるモノとしては
実装の詳細じゃなくてアーキテクチャの視点で語ってほしいです><
213:デフォルトの名無しさん
07/02/27 22:12:28
「相談室」なんだから、なにか適当なターゲットを想定するのが普通だろ
メタ論がやりたいならどっか適当にスレ立てろよ
これがほんとにマルチスレッド
214:デフォルトの名無しさん
07/02/27 23:34:05
そういうアクセスははなからそういうあくせすという前提で特別に処理を書くんじゃないの?
intでもアトミックに読めないとか、そういう問題とは別次元だろ。
215:デフォルトの名無しさん
07/02/27 23:35:07
わざとあえて意識してそういうことをしないとそういうことは起こらない。
216:195
07/02/28 01:26:31
>>210
>>209は自分じゃないんで・・・。
他の方も書いているように、CodecみたいにCPUベタベタな
最適化を行う場合を考えてもしょうがないかと。
今のところは>>189や>>196みたいなケースの場合にvolatileで
不十分な証拠は(処理系依存を除いて)出ていないんじゃないですか?
そんなわけで、今のところ>>180から進展はなさそうに思います。
>>213
自分はPCサーバクラスで使われるCPU辺りをメインに書いてます。
今はノートですらDual Coreだったりするので、その辺りも含めて
昔で言うワークステーションクラスまででしょうか。
217:デフォルトの名無しさん
07/02/28 02:53:24
言語組み込みの volatile で全部済ませられると主張するなら、
「あぁそうだといいね」とも思えるが、場合によってはロックが必要なことは
理解しているようだし。そうなると細かいこと考えずに全部ロックしとけば
いいと考えそうなもんだ。
なんでそんなに必死になってまでロック使いたくないの?
わざわざ保証されてないコード書くメリットが何かあるの?
218:デフォルトの名無しさん
07/02/28 06:28:24
このスレは頭ごなしにmutex使えやゴラーというやからが多いから意固地になってるのだろう。
結論はそうなんだけど、そこに至る過程を検証したいというのも分からないではない。
mutexの中の人が何をやっているかとか、実際身近にあるPCで賢い小人さんがどう働いているかとか、
そういう話題なら問題は無いだろう?
219:デフォルトの名無しさん
07/02/28 13:20:29
>>217
>なんでそんなに必死になってまでロック使いたくないの?
実行コストに決まってるだろ。
実行コスト無視できるなら、スピンロック、read-writeロック、プロセス内Mutex、プロセス間Mutex、
の使い分けなんて必要ない。
ただ、volatileで生成されるコードと、他のロックでどちらがコストが高いかは知らん。実行系によるし。
220:デフォルトの名無しさん
07/02/28 13:51:46
スレッド間で変数を共有する場合問題になるのは次の4つくらいか。
1)変数のレジスターへのキャッシュ。
2)コンパイル時の命令の並び替え。
3)CPUによる命令の並び替え(out of order)
4)CPUキャッシュ間の非同期。
1,2はコンパイラの仕事。
3は単一CPUでは発生しない。マルチCPUでは両方のケースがある。
4は単一CPUでは発生しない。マルチでもコヒーレント(一貫性)が保障されている処理系が多い。
3,4が発生しないでメモリー更新の順番が正しく見える構成をstrong memory orderと呼ぶ。
volatileだと1,2でかつアトミックな操作ができる単独の変数のみ。
メモリバリアは1,2,3,4すべてを満たしていて、
同期系のファンクションを使えばメモリバリアは適切に適用される。
書き込みが1スレッドで多数の読み込みスレッドがある場合に通常のLockが負荷が高いようなら、
ReadWriteLockとかInterLockとかそういったものを検討すべきだろう。
221:デフォルトの名無しさん
07/02/28 13:57:54
>>195
>いつまで経っても同期されないような腐ったCPUってあるの?
>あったとしたら処理系としてBrokenだよなぁ・・・。
ないとは言い切れない。互換性、安全性をとるなら同期ファンクションを使っておこう。
windowsXPまではstrong memory orderを前提にしているらしい。
MSDNのvolatileの説明が変なのはこのためだろうか。
移植性を無視してターゲットを絞るなら独自にいろいろやるのもありかもしれないが、
windows2003(今のところItanium用だけらしいけど)からは上記の3,4があるweak memory orderも
視野にいれているらしいから、こういうヴァージョンアップ時に困るな。
222:デフォルトの名無しさん
07/02/28 17:09:18
組み込み用だとキャッシュの同期なんて全くしない環境もあるようだが、
(そもそもCPUがマルチプロセッサ用に作られていない)
そういう環境にマルチスレッド対応のOSが移植されてるかは、
ググってみたが見つからなかったな。
一昨年あたりから、組み込み用CPUでもキャッシュ同期メカニズムを
持った物が出てきたようで、SMP対応のlinuxが移植されてたりするけど。
223:195
07/02/28 17:27:11
>>218
ほぼそんなとこです。
あとは、なんでPOSIX ThreadsにCASがないのか、とかね。
プリミティブ志向な設計なんだから追加されてもいいのに。
有名どころのアプリのいくつかは自前で実装してたりするし。
>>221
そりゃないとは言い切れないでしょ。
でもそういうのって、二の補数表現や1byte=8bitを仮定して
プログラムを書くのは良くないってのと同じなんじゃないの?
1word=36bitみたいな変態アーキテクチャを相手するのと一緒。
224:デフォルトの名無しさん
07/03/01 00:19:15
_beginthreadの使い方について質問です。
子スレッドの処理が止まっているとき、終了する方法が知りたいです。
-----------------------------------------------------------------
//子スレッドの関数
void thread_func(){
//Sleep();やソケットのaccept関数など永久に待つ関数などで、
//処理が止まっているので終了状態になりません
}
//子スレッド呼び出し
thread_id = _beginthread(thread_func,0,(void *)param)
//終了処理
GetExitCodeThread( thread_id,lpExitCode );//終了コード取得
ExitThread(lpExitCode );//終了コード指定して終了
CloseHandle(thread_id);//ハンドル閉じる
-----------------------------------------------------------------
1、子スレッドのsleep、accept関数など待ち状態を、解除する方法あるでしょうか?
処理が進めば、_endthreadで終了することが出来きるのですが。
2、強制的に親スレッドから、安全に子スレッドを強制終了する方法あるでしょうか?
_beginthreadは、CreateThreadを呼んでるみたいなのですが、上記のように
"//終了処理"しても大丈夫でしょうか?安全な方法教えていただけないでしょうか。
よろしくお願いします。
225:デフォルトの名無しさん
07/03/01 00:19:22
>>223
なんで良くないと言われていることをわざわざやりたがるの?
226:sage
07/03/01 00:43:41
>>225
良くないって、仕様で未定義だからってだけでしょ?
検証もせずに「お母さんが駄目って言ってたから」な方が嫌。
227:デフォルトの名無しさん
07/03/01 01:06:04
>>226
最近のレスでロック API の仕様の根拠となるものはあらかた提示されたんじゃないの?
228:デフォルトの名無しさん
07/03/01 01:22:09
>>224
とりあえず、
・必要なら、子スレッドでは極力タイムアウトするAPIを使う
・_beginthread()の場合、スレッド関数の戻りで子スレッドのハンドルは自動開放されるので
明示的に開放する必要はない
・少なくとも_beginthread()のハンドルにCloseHandle()を使うのは間違い
きちんと対応する関数をセットで使わなければいけない
・ただ、親スレッドでExitThread()したら、その後のCloseHandle()は実行されないよ
・子スレッドの安全な中断方法はない。
突っ込み所満載すぎるので、MSDNなりナニなりよく読むべし。
229:デフォルトの名無しさん
07/03/01 03:23:13
>>228
タイムアウト処理を考えるという方針でいきたいと思います。
sleepは時間を短くすればいいですし、
acceptは、selectを使ってrecvのタイムアウト関数(timeoutRevcとします)
と同じにすれば、timeoutAccept関数作れるかもしれないです。
・timeoutAccept抜けたら、はじめの一回目は、ソケットが読み込めるのわかってるので普通のrecv関数を呼ぶ。
・次の受信から、timeoutRevc呼ぶ感じでしょうか。
いくつも箇条書きでアドバイス、ありがとうございました。
230:デフォルトの名無しさん
07/03/01 07:04:23
229です。
acceptする前に、select関数使えないんでしょうか。
FD_ZERO(&readfds);
FD_SET(soc,&readfds);
select(width,&readfds,NULL,NULL,&timeout)
socは、きちんと渡せていたんですが、接続試しても
select抜けられずに、全部タイムアウトになります。
accept呼んでからじゃないと、ソケットの読み取り可能か
わからないかもです。
スレ違いになりますので、ネットワークのスレに行きたいと思います。
ありがとうございました。
231:デフォルトの名無しさん
07/03/01 11:14:25
やべーvolatile最強すぎる
「volatileが最強でない環境って存在するの?」
「現存しないからvolatile最強wwwwwwwwwwwwwwwwwwww」
>>161 でFA出てるしwww
232:デフォルトの名無しさん
07/03/01 11:18:50
2000年問題に通じるものがあるな
233:デフォルトの名無しさん
07/03/01 12:28:10
[すれ立てるまでもない質問はここで]
で聞いてたんだが、此処で聞いた方が良いかと思ったので、
再質問させてもらいます。
Windows MFCでマルチスレッドは止めておいた方が良い
と、良く聞くんだけど、具体的にどんな問題が発生するのか
掲示しているところが無いんだけど、どうしてMFCでの
スレッドは嫌われるのか教えてもらえないでしょうか。
単なる好奇心なので、仮説でもうれし。
234:デフォルトの名無しさん
07/03/01 12:42:43
誰が言ってんだ、そんなこと。
235:デフォルトの名無しさん
07/03/01 12:48:10
>>233
それま色々なスレで同じ質問をしないほうが良いと言われただけでは?
236:デフォルトの名無しさん
07/03/01 12:50:14
>>233
とりあえず移動元に誘導書いておけよ、マルチ扱いされるぞよ。
俺も聞いたことない。
237:デフォルトの名無しさん
07/03/01 13:27:04
MFCに限らず、マルチ(複数の)スレッドで質問するのは良くない。
238:デフォルトの名無しさん
07/03/01 14:21:41
ワロタ
239:デフォルトの名無しさん
07/03/01 16:05:38
>>224
つ URLリンク(support.microsoft.com)
240:233
07/03/01 16:17:27
>>234
>MFC のシステムそのものがマルチスレッドに向いていない。
URLリンク(www.kab-studio.biz)
さすがにどこで見たかを思い出せなかったので検索して
出てきたのが例えばこれとか。
>>236
>>237
移動元に書いてきたよ。
ごめんよ。
241:デフォルトの名無しさん
07/03/01 17:05:31
>>240
WaitForSingleObjectで待つんじゃなくて自イベントで通知
MFC関係なくないか?
読みづらいし会話式がアレだな
242:デフォルトの名無しさん
07/03/01 17:17:57
UIスレッドは確かに使わないかもしれない。向いてないとか難しいとかいうより必要性が薄い。
ワーカースレッドについては特にMFC特有の問題じゃないな。
243:デフォルトの名無しさん
07/03/01 18:03:52
>>240
じゃあ、そのサイトが間違い。
いや間違いというか、MFCがマルチスレッドに対して便利な機構を用意しているかというとNoだけど、
マルチスレッドを意識してないわけじゃない。つまり、ユーザーからロックできないグローバル変数、
クラス変数はロックしてる。
なんで、ユーザーからロックできる部分については、勝手にロックして、スレッドセーフにしろよ、
ってスタンス。それを「向いてない」と表現するかどうかは人による。
・MFCとマルチスレッドの関係 (Afx...でのMFCグローバル情報へのアクセス等)、
・Win32とマルチスレッドの関係 (SendMessageがらみのウィンドウループの把握、WinSockでのWM_を使った非同期処理等)、
・一般的なGUIシステムにおけるマルチスレッドの作法 (GUIスレッドを止めない、長時間処理は別スレッド、非同期化等)
を分けて考えるべき。
244:デフォルトの名無しさん
07/03/01 18:24:21
まぁMFCはガベコレがないという致命的欠点を持っているなんて
Wikipediaに書かれるほど挫折した連中に嫌われているってことだな。
245:デフォルトの名無しさん
07/03/01 18:47:00
> それを「向いてない」と表現するかどうかは人による。
「俺はマルチスレッドなプログラムなんかできないから、ライブラリか何かでどうにかしてくれよ」という人?
「これさえ使えばあら不思議。マルチスレッドなプログラムが簡単に!」とか。
>まぁMFCはガベコレがないという致命的欠点を持っているなんて
これは笑いどころですか?
246:243
07/03/01 19:03:59
>> それを「向いてない」と表現するかどうかは人による。
>「俺はマルチスレッドなプログラムなんかできないから、ライブラリか何かでどうにかしてくれよ」という人?
>「これさえ使えばあら不思議。マルチスレッドなプログラムが簡単に!」とか。
いや、俺に言われても。
247:244
07/03/01 19:38:14
>>245
> これは笑いどころですか?
いや、俺に言われても。
248:244
07/03/01 19:57:04
>>247
いや、そこで騙られても。
249:デフォルトの名無しさん
07/03/01 21:02:37
MFCにガベコレを求めるとかバカとしか思えない
250:デフォルトの名無しさん
07/03/01 21:11:36
244はそんなことを言ってるわけじゃないんだが。
改行位置のせいで勘違いするのも分からんでもないが。
251:デフォルトの名無しさん
07/03/01 21:27:35
このスレのガベージをコレクトしたい
252:デフォルトの名無しさん
07/03/01 22:08:15
/ ____ヽ /  ̄  ̄ \
| | /, −、, -、l /、 ヽ
| _| -| ・|< || |・ |―-、 |
, ―-、 (6 _ー っ-´、} q -´ 二 ヽ |
| -⊂) \ ヽ_  ̄ ̄ノノ ノ_ ー | |
| ̄ ̄|/ (_ ∧ ̄ / 、 \ \. ̄` | /
ヽ ` ,.|  ̄ | | O===== |
`− ´ | | _| / |
| (t ) / / |
「>1からマークスイープでGCするよ!」 「コンパクションも忘れずにね」
1時間後…
,-―-、 ___
{ , -_−_− / _ _ ヽ
.(6( /),(ヽ| / ,-(〃)bヾ)、l
/人 ー- ソヽ _ | /三 U |~ 三|_
/ / |  ̄_∧/ ヽ |(__.)―-、_|_つ_)
| | \/_/-、 / / /`ー--―-´ /
|-\ _|_ )_| / | // ̄( t ) ̄/
ヽ-| ̄| |_|_ / ,− | | ヽ二二/⌒l
/ l―┴、|__) | (__> -―(_ノ
/ `-―┘ / `- ´
/
「>1しか残らなかった…」 「テンプレへのリンクもなかったのか!」
253:デフォルトの名無しさん
07/03/01 22:48:55
>>251
[゚д゚] ・・・?
/[_]ヽ
| |
254:デフォルトの名無しさん
07/03/01 23:53:37
>>253
おまえは呼んでない
255:デフォルトの名無しさん
07/03/04 02:15:45
pthreadのPTHREAD_MUTEX_INITIALIZERのように、
win32のCRITICAL_SECTIONを静的に初期化する方法はありますか。
現在は仕方が無いので
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
で済むところを
static pthread_mutex_t mutex;
static int initialized;
static int lock;
if (!initialized && InterlockedIncrement(&lock) == 1) {
pthread_mutex_init(&mutex, 0);
initialized = 1;
}
などと書きました。
なお、↑のコードでは、とりあえず
#define pthread_mutex_t CRITICAL_SECTION
#define pthread_mutex_init(A,B) InitializeCriticalSection(A)
#define pthread_mutex_lock(A) (EnterCriticalSection(A), 0)
#define pthread_mutex_unlock(A) (LeaveCriticalSection(A), 0)
#define pthread_mutex_destroy(A) DeleteCriticalSection(A)
などと定義しています(極めてうさんくさいですが)。
256:デフォルトの名無しさん
07/03/04 04:38:29
>>255
class CriticalSection
{
CRITICAL_SECTION csect;
public:
CriticalSection() { InitializeCriticalSection(&csect); }
~CriticalSection() { DeleteCriticalSection(&csect); }
void Lock() { EnterCriticalSection(&csect); }
void Unlock() { LeaveCriticalSection(&csect); }
operator LPCRITICAL_SECTION() { return &csect; }
};
class Lock
{
CriticalSection& save_cs;
public:
Lock(CriticalSection& cs) : save_cs(cs) { save_cs.Lock(); };
~Lock() { save_cs.Unlock(); }
};
257:デフォルトの名無しさん
07/03/04 04:40:47
static CriticalSection cs1; // で初期化しておいて下のように使える。
void func(){
Lock lock(cs1);
//
}
void func(){
cs1.Lock();
//
cs1.Unlock();
}
258:デフォルトの名無しさん
07/03/04 05:07:50
というやり方だと、
コンパイラの吐く「ローカルな静的変数の初期化コード」に排他処理が行われないため
グローバル変数(staticメンバでも良いが)にしか使えない。
で、過去スレに書いたが
CriticalSectionへのポインタとInterLockedExchangePointerを使えば
ローカルな変数でも、排他しながらの初期化及び実行が行える。
259:デフォルトの名無しさん
07/03/04 05:21:53
なるほど。C++のstatic objectの初期化機能を利用する訳ですね。
Cでは使えないテクニックですね……。
>>255のコードには不備がありました。
2コ目以降のスレッドがInitializedCriticalSection()実行前に
下に流れてしまう可能性があるので、
上のコードの後で
while (!initialized) Sleep(1);
としなければなりませんね。
260:デフォルトの名無しさん
07/03/04 05:48:19
>>258
>で、過去スレに書いたが
目を通しておきたいのですが過去スレというのはこのスレですか?その4以前?
最初のロックまでCRITICAL_SECTIONの初期化を遅延したいとか
考えない限り大丈夫のように思えるけど。
261:デフォルトの名無しさん
07/03/04 05:48:40
んー、だから
static CRITICAL_SECTION *p = NULL;
if (!p) {
CRITICAL_SECTION *q = new ...;
Interlocked...(&p, NULL, q); //引数の順番忘れた
if (p != q) {
delete q;
}
}
EnterCriticalSection(p);
...
Leave...();
なら、Cでも使えるよ。
262:デフォルトの名無しさん
07/03/04 05:53:34
で、C++なら、これをclassにまとめて
#ifdef _WIN32 で切り分けてPTHREAD_MUTEX_INITIALIZERと使い分けると楽だよ。
ただ、必ずstaticなオブジェクトとして使わないといけない、ということを
分かった上で使わないといけないけど。
263:デフォルトの名無しさん
07/03/04 05:57:13
あ、Initializeとか忘れてたけど
まあ分かるでしょ
264:デフォルトの名無しさん
07/03/04 06:12:45
>>261
new, deleteがCでも使えるというのは冗談でしょう。
if (!p) {
CRITICAL_SECTION *q = new ...;
これは、この部分に2コ以上のスレッドが同時に突入した場合、
2度以上InitializeCriticalSection()を実行させたいという意味ですか?
265:259
07/03/04 06:15:36
> while (!initialized) Sleep(1);
このように書きましたが、これはWin32環境で合法なのでしょうか。
マルチコアのシステムではまずかったりしますか。
MSVC++で-Ox最適化をかけたアセンブリコードを眺める限り、
一見動きそうに思えますが、いまいち自信がありません。
266:260
07/03/04 06:16:08
>>261
初期化を遅延する場合ですね。それなら了解。
267:デフォルトの名無しさん
07/03/04 07:08:09
>>264
newが使えない事くらい、わかった上で書いたんだけど(面倒だから)
そんな本質的じゃない部分を指摘してうれしい?
件の部分は、(ほぼ)同時に突入したら、当然複数初期化される。
けど、続く部分で、実際に代入されるのは一つであることが保証される。
(最初に実行されたスレッド以外からのCASは失敗する)
だから、それを実行した後、自スレッドで初期化した値とpが違っていたら
それを破棄して、全スレッド共有の値でロックを実行すればよいだけ。
まあ、俺が偉そうな事言いたくて書き込んだだけだから、あまり気にするな。
普通に非ローカルな静的変数とC++のインスタンス初期化を使うのが
いちばん簡単だし、わかりやすいし、無駄も無い。
初期化順が問題になることも無いでしょ。
268:259
07/03/04 07:17:53
>>267
> そんな本質的じゃない部分を指摘してうれしい?
気を悪くされたならすみません。
Cで書いた場合のコードに、>>255と本質的な違いがあるのか?と
問いたかっただけです。
newが使えないだけではなく、クラスも使えませんよね。
>>261は全くCのコードではありません。
> 件の部分は、(ほぼ)同時に突入したら、当然複数初期化される。
単に複数回初期化されるだけでなく、メモリリークが発生しますね。
269:デフォルトの名無しさん
07/03/04 08:14:12
> メモリリークが発生しますね。
だからわざわざ(本来なら省略しても良い)deleteまで書いたんだけど?
270:デフォルトの名無しさん
07/03/04 08:17:06
まさかとは思うけど
「実行中に確保(初期化)されて、終了時でも解放されないままのもの」
という意味で「メモリリーク」という言葉を使っている、
More Effective C++すら読んでないような初心者だったら、ごめんよ。
271:デフォルトの名無しさん
07/03/04 08:20:53
>>268
>>261はいろいろ省略してるのだけど、InterlockedCompareExchangePointerを使えといってるのだと思うよ。
>Cで書いた場合のコードに、>>255と本質的な違いがあるのか?と
>問いたかっただけです。
どちらも遅延初期化で本質的な違いはなさそうだけど、
>>261はダブルチェックロッキングが正しく出来ているが>>255には穴がある。
272:259
07/03/04 08:27:12
>>269
理解しましたm(_ _)m
他スレッドのInterlockedExchangePointer()によって値が変えられていたら
deleteするという意味なのですね。
Cで書くと
static CRITICAL_SECTION *p = 0;
if (!p) {
CRITICAL_SECTION *q = malloc(CRITICAL_SECTION);
InitializeCriticalSection(q);
InterlockedExchangePointer(&p, q);
if (p != q)
free(q);
}
でしょうか。
273:259
07/03/04 08:30:03
んが。
malloc(sizeof(CRITICAL_SECTION));
ですね。
それと。InterlockedExchangePointer()ではなく、
InterlockedCompareExchangePointer()を使わなければならないのですか。
むずかしい...。
274:259
07/03/04 08:32:30
>>271
>>255のコードの穴というのは、>>259に書いたのとは別のものでしょうか。
275:デフォルトの名無しさん
07/03/04 09:21:12
あーそうか、ほんとごめん。
確かに>>271の通り、CompareExchangeの方のこと(つまり>>258が俺の凡ミス)。
俺が重要な部分を間違えていたのに、意図を理解してくれる人がいてくれて助かった。
他の人も含め、ごめんね。
>>259では、本質的な解決にならないと思うよ。
つまり、比較(テスト)と初期化(&代入)の間に他のスレッドに割り込まれる可能性を消すには
atomicなCASを実行するしかないって事。
276:デフォルトの名無しさん
07/03/04 09:31:57
あ、そうか、>>255を見るとInterlockedを使っているのか。
でも、InterlockedIncrementは正負と0しか判定できないんじゃなかったかな。
で、仮に
初期値を-1として
2^32個以上のスレッドが同時に初期化部に入ることは有りえないとして
>>259の修正(Inc失敗なら他のスレッドを待つ)を加えて
当然volatileにして
とすれば、正常に動くのかな。
でもそこまでするなら、やっぱりCASを使う方がまともかと。
277:259
07/03/04 09:40:12
>>276
はい。CAS方式がエレガントでまともなコードであると納得できました。
Sleep()ループで待つなんてカッコ悪いことは出来ればしたくありません...。
有難うございます。
278:デフォルトの名無しさん
07/03/04 09:45:22
ここまでやれば大丈夫だと思うけど。
if (!initialized)
if(InterlockedIncrement(&lock) == 1) {
pthread_mutex_init(&mutex, 0);
initialized = 1;
メモリバリア〜〜
} else {
while (!initialized) {
Sleep(1);
メモリバリア〜〜 またはinitializedが揮発性であることが必要
}
}
}
老婆心から言えばスレッド生成前までに作っておいたほうがよいと思う。
スレッド生成後の初期化なんてバグの元。
PTHREAD_MUTEX_INITIALIZERマクロが何をやってるか調べてみたら何かヒントがあるかもしれないね。
javaで有名になったダブルチェックロッキングの話はまだ半分くらいしか理解できてないしなorz
279:デフォルトの名無しさん
07/03/04 09:47:50
InterlockedIncrementはWin95以前だと正負と0の判定しかできないので>>255のようには使えないよね。
あと厳密に言えばの話だけど
このスレの上のvolatile関連の議論からするとinitialized=1;の変更がキャッシュのせいで
他のスレッドに伝わらないかもしれない(規格的には)ので>>255のinitializedにはlock命令が必要だけど
lock命令を追加しようとすると結局>>261みたいになってしまうんじゃないかな。
別に言わなくてもわかるだろうけど
>>255は volatile static int lock = 0;
>>272は
volatile static CRITICAL_SECTION *p = NULL;
if (p != q) { DeleteCriticalSection(q); free(q); }
280:デフォルトの名無しさん
07/03/04 09:49:12
> PTHREAD_MUTEX_INITIALIZERマクロが何をやってるか
これはさすがに定数値を{}なりで囲んでるだけだと思うけど。
Cでも使えるんだし。
281:259
07/03/04 09:52:14
PTHREAD_MUTEX_INITIALIZERは単に{ 0 }
とかだと思います。
>>279
うわ。赤面しまくりです...。
ぶっちゃけUnixベースのライブラリをちょろっといじくってWin32に
移植しようと思っただけなのですが、こんなワナが待っていたとは
思ってもいませんでした。
282:デフォルトの名無しさん
07/03/04 10:24:41
下の例の場合変数iにvolatileは必要かどうか質問です。
lock, unlockがメモリバリアだから必要ないという認識なのですがつけている例も見ます。
>>261だとlockせずに読んでる箇所もあるので必要なのかもしれませんが、
この辺の基準ってどうされていますか?
int i;
thread_function() {
mutex.lock()
i = i + 1;
mutex.unlock()
}
283:デフォルトの名無しさん
07/03/04 10:32:03
だれか
.NET Frameworkのメモリモデルとかに詳しい人おらんかね?
284:デフォルトの名無しさん
07/03/04 10:42:25
>>282
付けといた方がいいんじゃない?mutexのメモリバリアでcpuキャッシュの同期は取れても
スタックやレジスタに積まれたままだったら意味ないしね。
285:デフォルトの名無しさん
07/03/04 11:17:03
>>283
設計上はウィークメモリオーダリングということなので、OoOあり〜の、コヒーレンシキャッシュは信用できね〜のです。
今のところ実装上はx86系のWindows上ではストロングメモリオーダリングのみ。
Itaniumは構成によってウィークメモリオーダリングもある得るそうです。
286:デフォルトの名無しさん
07/03/04 11:51:52
ところが、CLR2.0では書き込みオーダは保証されてて、
今後もそうだと約束されてるらしい。
それはおいといて、よく理解できてないのが、
書き込みスレッドでメモリバリアを実行した場合、
読み込み前のメモリバリアは必要なのかどうか。
あるメモリ領域に書き込みしてメモリバリア実行、その後完了フラグセット。
別スレッドで完了フラグを確認してからメモリ領域を読み込みってときに、
完了フラグ確認後にメモリバリアは必要なのかどうか。
なんとなく読み込み順が保証されないから必要な気もするんだが、
.NETのメモリバリア命令はフルメモリバリアだから不要?ってのも見た。
.NETのメモリバリアは別プロセッサの読み込みキャッシュもクリアして
かつJITの最適化とかで先読みとかがおこらないなら大丈夫なんだと思うんだけど
この方面素人なのでいまいちよく分からない。
287:デフォルトの名無しさん
07/03/04 11:53:25
メモリバリアの説明には、このプロセッサ上でキャッシュをフラッシュするとかって説明になってんだよね…
288:デフォルトの名無しさん
07/03/04 13:04:32
Itaniumだと、そもそもout of orderしないですな。
命令の並べ替えや並列化はすべてコンパイラの仕事だ。
289:デフォルトの名無しさん
07/03/04 13:11:11
だからこそ その辺の事情は本来プログラムで意識したくないよな・・・
DCLの欠点なんて最たるものだし
290:デフォルトの名無しさん
07/03/04 17:17:43
>>282
メモリバリアだから必要ないという認識では、ちょっと違うね。
関数呼び出しをまたいでグローバル変数をキャッシュできないから
volatileが必要ないというのが本質。
変数をレジスタ等にキャッシュしていないからこそ、メモリバリアが有効になる。
仮にlockやunlockをインライン展開できるようなコードで実装できたとすると
while() { lock(); i = i + 1; unlock(); } はvolatileが無いと危険かもしれない。
291:デフォルトの名無しさん
07/03/04 19:41:48
>>290
それは本質じゃなく単なる実装の話だと思います。
たとえばmsvc++などは次の理由からそういう実装になっています。
現在のx86系WindowsはOoOはやっててもアプリからは見えないハード的な仕掛けになっていますし、
コヒーレントキャッシュもある前提なのでキャッシュによる不整合もありません。
x86はレジスタの数が少ないので関数呼び出しのタイミングで変数をメモリ上に書き出します。
たとえばpthreadのmutexではvolatileは不要とドキュメントにあります。
すべてのコンパイラがそうなってるかどうかは分かりませんが、少なくともスレッド系のライブラリと一体で
提供されている環境ではサポートされているはずです。
292:デフォルトの名無しさん
07/03/04 20:23:08
>>291
インライン展開できない関数を呼ぶ前は、x86であろうと無かろうと
非ローカル変数をキャッシュできないよ。
レジスタの数が問題なのではなく、非ローカルな変数は呼び出した先で
更新される可能性があるから。
293:デフォルトの名無しさん
07/03/04 21:03:48
あと、ローカル変数でも、アドレスを取って他の関数に渡している場合に
その前と後で変数の中身が変更される可能性は、コンパイラも考慮しているはず。
だから例えば>>255のlockや>>272のpにはvolatile不要なはず。
もちろん、>>255のinitializedには必要だけどね。
で、pthread_mutex_tも、アドレスを取って渡すのだからvolatile不要、
という考え方でも充分かもしれない。
ただし、アドレスを取って呼び出した関数から戻った後に
変数の中身が他のスレッドによって変更される可能性は考慮されないので
レジスタにキャッシュされるかもしれない。
それが問題になる可能性がある(コードで中身を参照している)ならば
volatileが必要になるね。
294:デフォルトの名無しさん
07/03/04 21:29:48
>>292
確かにそこは例えが悪かったので取り消します。
(PGOのような広域のインライン展開のことを考えていたのですが論旨に合わないようです)
言いたかったのは同期関数の呼び出しのタイミングで
偶然レジスタとメモリの同期が取られているという話ではなく、
メモリバリア実現の属性のひとつとして関数の呼び出し時にレジスタとメモリの同期が
とられるという仕組みが利用されてるということです。
だから、レジスタとメモリの同期以外にCPUキャッシュ間の同期やOoOの調整が必要ならば
その処理が同期関数に含まれていなければならないと考えているわけです。
295:デフォルトの名無しさん
07/03/05 18:53:41
____
/ \
/ ─ ─\
/ (●) (●) \馬鹿ばっか
| (__人__) |
\ ` ⌒´ /
ノ \
/´ ヽ
| l \
ヽ -一''''''"~~``'ー--、 -一'''''''ー-、.
ヽ ____(⌒)(⌒)⌒) ) (⌒_(⌒)⌒)⌒))
296:デフォルトの名無しさん
07/03/05 22:57:17
volatile旋風スゴス
297:デフォルトの名無しさん
07/03/10 22:35:07
質問です。
while ( count > 1 ){
pthread_cond_wait( &cond_t, &mutex );
}
この場合、条件変数と呼ばれるものはcountですか?
それともcond_tになるのでしょうか?
また、countのチェックにifは使ってはならない。と言われたのですが、
なぜだか解りません。
上記の部分と、
while (1){
if( count > 1 ) pthread_cond_wait(ry);
}
は同じだと思うのですが・・・
よろしくお願いします
298:デフォルトの名無しさん
07/03/10 22:51:41
>>297
while (1)
{
if( ! (count > 1) ) break;
pthread_cond_wait(ry);
}
と同じだと思う。
299:デフォルトの名無しさん
07/03/10 23:04:21
>>298
そうでした。すんません
300:デフォルトの名無しさん
07/03/10 23:33:31
> 条件変数と呼ばれるものはcountですか?それともcond_tになるのでしょうか?
条件変数はcond_t。!(count>1)は述語。
> countのチェックにifは使ってはならない。と言われたのですが、
言った本人に聞けばいいと思う。いけないってことは無いと思う。
pthread_mutex_lock(&mutex);
while (!pred(ry))
pthread_cond_wait(&cond, &mutex);
pthread_mutex_unlock(&mutex);
というのが定型パターンの予感はするんで、
その人にとって奇怪なコーディングするなという意味かもしれん。
301:デフォルトの名無しさん
07/03/11 08:33:14
ありがとうございます。
countは述語っていうのですか。知りませんでした。
>ifでんでん
後でもう一度聞いてみます。
302:デフォルトの名無しさん
07/03/11 11:25:05
でんでんってなんだ。云々(うんぬん)と言いたいのか、わざとボケてるのかどっちだ。
303:デフォルトの名無しさん
07/03/11 12:35:43
>>302
単なる2chのジャーゴンだから気にするな
304:デフォルトの名無しさん
07/03/11 14:17:43
countが述語なんじゃなくて
"count>1"が述語
countは単なる変数
305:301
07/03/11 15:38:51
>>304
"count>1"で、述語。ですか。解りました。
ありがとうございます。
>>でんでん
"うんぬん"で"云々"ですか。初めて知りました
ゆとり年代より一つ上なはずなんだけどゆとりでごめんなさい
306:300
07/03/11 15:43:08
ごめん。!(count>1)でなく、count>1だった。
301に幸あらんことを。
307:デフォルトの名無しさん
07/03/11 15:43:39
俺がかつて1日だけ流行らそうとしてばら撒いてたでんでんが意外な影響を。
308:デフォルトの名無しさん
07/03/11 16:04:43
「云々」を「でんでん」ってことは
「云」を「でん」と読んでるって事だよな。
俺、そもそも「云」という漢字、単独でどう読むか知らないのだが。
309:デフォルトの名無しさん
07/03/11 16:29:44
>>308
「ウン」でしょ。
310:デフォルトの名無しさん
07/03/11 16:37:38
伝が“でん”だからなあ
311:デフォルトの名無しさん
07/03/11 20:45:06
雲が「うん」と読まれることには頓着しないらしい。
312:デフォルトの名無しさん
07/03/11 22:22:20
ワンタン
雲呑
313:デフォルトの名無しさん
07/03/12 00:36:16
うーんぬんむーしむし、かーたつむりー
314:デフォルトの名無しさん
07/03/16 09:25:59
____
/ \
/ ─ ─\
/ (●) (●) \ 「テラワロスwwwwwwwうぇうぇwwww」・・・・と
| (__人__) | ________
\ ` ⌒´ ,/ .| | |
ノ \ | | |
/´ カタ. | | |
| l カタ | | |
ヽ -一ー_~、⌒)^),-、 | |_________|
ヽ ____,ノγ⌒ヽ)ニニ- ̄ | | | ____
315:デフォルトの名無しさん
07/03/20 00:12:35
ごめん書籍いいでしょっていわれてるけれど
マルチスレッドの勉強する本をおしえてほしいの
316:デフォルトの名無しさん
07/03/20 00:32:02
マルチスレッドについて本で得られるものは1%もない。
といっては見もふたもないので、もう少し具体的にマルチスレッドで何をしたいの?
OSは?マルチスレッドアプリ?APIがしりたい?それともカーネルの実装(はないよな)?
317:デフォルトの名無しさん
07/03/20 15:54:59
Unix 方面の人は「実践マルチスレッドプログラミング」
Win32の人は「Win32マルチスレッドプログラミング」
当り前のことが当たり前に書かれてるだけで、
別にいいも悪いもないけど。
このあたりに出てくるような概念、問題、手法については常識として理解した上で、
新しい手法やOS/CPU/言語毎のメモリモデルなどについての知識を深めると、
volatile 論議とかで無駄に遊べる。
318:デフォルトの名無しさん
07/03/20 23:15:04
>>315
Java使いなら↓は超オススメ。
URLリンク(www.amazon.co.jp)
邦訳版もあるよ。
319:デフォルトの名無しさん
07/03/21 00:27:18
>>317
素朴な疑問
> Unix 方面の人は「実践マルチスレッドプログラミング」
> Win32の人は「Win32マルチスレッドプログラミング」
この辺を読めば volatile 最強って言い切れるようになるんですか?
320:デフォルトの名無しさん
07/03/21 03:30:37
317をもう一度よく読んだほうがいいんじゃない?
321:デフォルトの名無しさん
07/03/21 04:34:08
自作自演の可能性
322:デフォルトの名無しさん
07/03/21 13:51:09
volatile厨を論破するのはそんなに簡単じゃないよ。
323:デフォルトの名無しさん
07/03/21 15:55:04
NG登録するだけだし
324:デフォルトの名無しさん
07/03/24 10:03:31
Win32の本ってオライリーのやつのことでいいの?
325:デフォルトの名無しさん
07/03/24 15:56:09
>>315
並行プログラミングの原理―プロセス間通信と同期への概念的アプローチ (単行本)
326:デフォルトの名無しさん
07/03/27 14:50:58
____
/ \ /\ キリッ
. / (ー) (ー)\
/ ⌒(__人__)⌒ \ volatile厨を論破するのはそんなに簡単じゃないよ。
| |r┬-| |
\ `ー'´ /
___
/ \
クスクスッ /ノ \ u. \ !?
/ (●) (●) \
| (__人__) u. |
\ u.` ⌒´ /
____
/ \!??
/ u ノ \ クスクスッ
/ u (●) \
| (__人__)|
\ u .` ⌒/
327:デフォルトの名無しさん
07/03/27 22:33:12
Javaのsynchronizedとwaitとnotifyに関する質問なんだが
URLリンク(www.javaworld.jp)
ここの
class Buffer {
private int value;
private boolean isEmpty = true;
public synchronized void putValue(int v) {
while (!isEmpty) {
try {
wait();
} catch (InterruptedException e) { }
}
notifyAll();
isEmpty = false;
value = v;
}
public synchronized int getValue() {
while (isEmpty) {
try {
wait();
} catch (InterruptedException e) { }
}
notifyAll();
isEmpty = true;
return value;
}
}
これがどうして動くのか分からん。
あるスレッドがgetValueに入ってる間は、ほかのスレッドは
getValueにもputValueにも入れないんじゃないのか
328:デフォルトの名無しさん
07/03/27 22:34:13
すまんソースコードが見づらくなってしまった。
リンク先を見てくれ。
329:デフォルトの名無しさん
07/03/27 22:52:21
>>327
前のページで説明されてる。
330:デフォルトの名無しさん
07/03/27 22:53:08
URLリンク(sdc.sun.co.jp)()
の二段落目を理解できない無能?
331:デフォルトの名無しさん
07/03/27 23:05:42
すまんかった。
とんくす
332:デフォルトの名無しさん
07/03/28 08:53:09
____
/ \ /\ キリッ
. / (ー) (ー)\
/ ⌒(__人__)⌒ \ の二段落目を理解できない無能?
| |r┬-| |
\ `ー'´ /
___
/ \
クスクスッ /ノ \ u. \ !?
/ (●) (●) \
| (__人__) u. |
\ u.` ⌒´ /
____
/ \!??
/ u ノ \ クスクスッ
/ u (●) \
| (__人__)|
\ u .` ⌒/
最新レス表示スレッドの検索類似スレ一覧話題のニュースおまかせリスト▼オプションを表示暇つぶし2ch
4223日前に更新/97 KB
担当:undef