マルチスレッドプログ ..
[2ch|▼Menu]
71:デフォルトの名無しさん
09/09/24 01:47:24
すみません初歩的な質問で申し訳ないのですが,mutexで排他制御された場合、例えば
mutexlock();

A[0] = 0;

mutexunlock();

の様な場合、スレッドAはA[0]をアクセスして、スレッドBはA[100]をアクセスするとします。
その場合、スレッドBはスレッドAの処理が終わるまで配列Aにアクセスできないのでしょうか?

72:デフォルトの名無しさん
09/09/24 01:50:07
>>71
そうなるね

73:デフォルトの名無しさん
09/09/24 02:22:05
「の様な場合」なんていう他人に通じない省略しないで、
スレッドBの処理も書けばいいのに

74: ◆0uxK91AxII
09/09/24 04:50:22
>>71
//mutexlock();

A[100] = ~0;

//mutexunlock();

:b

75:デフォルトの名無しさん
09/09/24 06:02:29
>>71です。
しょうもない質問をしてすみません。mutexでロックをかけた場合、配列にアクセスする場合はその間配列全体がアクセス禁止になるのか、
それともその一部のみ(例えばキャッシュライン分)がアクセス禁止になるのかを知りたかったのです。
アクセスできないとなると、 int D[10000]位確保されていたとして、
int *A,*B,*C;
A = &D[0];
B = &D[1000];
C = &D[2400];
のようにポインタでAの場所を指して、
スレッドA: D[0]〜D[1199]の内容を書き換え、スレッドB:D[1200]〜D[2399]の内容を書き換え、スレッドC:D[2400]〜D[3599]の内容を書き換え、
オーバーラップする領域はまずAの処理を優先するため、その領域を保護するためにmutexでロックをかけている間、
BはAの処理が終わるのを待たなければならないのは分かるのですが、CもAの処理が終わるまで待たなければならないのでしょうか?

Thread A:
for(i=0;i<1200;i++){
mutexlock(mu);
    A[i]=100;
mutec_unlock(mu);
}
Thread B:
for(i=0;i<1200;i++){
B[i]=200;
}
Thread C::
for(i=0;i<1200;i++){
C[i]=300;
}


76:デフォルトの名無しさん
09/09/24 07:34:43
>>61
> 相当限定的な使い方しか出来ない気がするなぁ…。
> 「スレッドの状態を気にしなくて良い」んじゃなくて、
> 気にできないんじゃないの?

これ書いたの俺だけど、malloc() の内部処理辺りには
使えそうだと思った。それと類似して C++ の new() を
オーバーライドしといて予め準備しといたメモリプール
から取ってくるとかいうよくある奴。

例としてはそんなのでいいだろか? > 例を要求してた人

77:デフォルトの名無しさん
09/09/24 08:25:29
>>75
その例の場合は素通り
配列が自動的にアクセス禁止になるわけではない
ThreadBもThreadCもmutexをロックしてどこからどこまで保護するのか明確にしなければならない

78:デフォルトの名無しさん
09/09/24 09:17:59
>>77

ロックする範囲が限定されていれば、
他のスレッドは進行を妨げられずに処理できるのですね。
ありがとうございました。

79:35
09/09/24 11:56:35
>>60
記事の紹介、ありがとうございます。読んでみました。

記事では、C++でlock-freeを使って生産者-消費者モデルを実現していますね。
以下はすべてC++のWaitFreeQueueクラスとして実装されています。

・まずlock-freeで「排他」を実現するキューを実装。
 この時点では「排他」だけですから、スレッド間の「同期」は実現できていません。
・次に、キューが空である間、消費者スレッドをループさせ続けることで「同期」を実現。
 この方式では、キューが空であればCPUを100%消費します。
 ==> NATIVE_POOLING方式
・続いて、キューが空である間、消費者スレッドをスリープさせ続けるループを
 組むことで「同期」を実現。 ==> SLEEP方式
・最後に、BOOSTのcondition(timed_wait/notify操作)を使う事で、
 「同期」を実現。==> TIME_WAIT方式

(続く)

80:35
09/09/24 11:59:49
(>>79の続き)

このC++ by DDJ実装と、>>40が紹介してくれたJavaの実装とを比較すると、
lock-free/wait-freeの意味に違いがあるように感じられました。
C++ by DDJ実装のTIME_WAIT方式は、JavaであればBlockingQueueクラスに相当しますが、
>>40では、BlockingQueueクラスは(同期の実現はモニタ使用が前提だから)
lock-free/wait-freeではない、と定義しています。

これらの一見矛盾しているように見える事柄を、自分なりに以下のように解釈してみました。

・lock-free/wait-free単独では「同期を実現できない」
・ただし、lock-free/wait-freeとスリープ(あるいはモニタ/conditionなど)とを組み合わせた制御を
 アプリケーション側で(たとえばクラスとして)実装することで「同期を実現できる」

誰も皆「排他」に関しては「実現できる」と見解は一致していますが、
この「同期」が「実現できる/できない」という解釈に関しては、人によって見解が
分かれているように思えます。違いは、「スリープ/モニタ/conditionなど」の使用を含めて
「できる」とする考え方と、それらは純粋なlock-free/wait-freeではない、とする考え方です。
難しい論争で、技術的な課題でもありませんから、私もこれ以上の考察は止めにします。

81:35
09/09/24 12:10:08
>>70
レスありがとうございます。

>>80の最後で書いたように、lock-free/wait-freeとスリープとを組み合わせた制御を
アプリケーション側で実装することによって「同期」は実現できますね。

# せっかく>>60がDDJの記事を紹介してくれていたのに、それを読まずに>>69
# カキコしてたのが、まずかったと反省しています。余計な手間をとらせてごめんなさい。

82:デフォルトの名無しさん
09/09/24 12:24:59
リング遷移よりはスピンした方がいいとか、ある程度待っても何も来なかったら
スリープとか、待機時の特性をアプリケーションがチューニングするやり方に
なるのは、ハイパフォーマンス向けだと利点と言えるのでは。
まぁ、リング遷移が気にならない状況ならカーネルに任せていいと思うけど。
とりあえず、スピン待機は立派な同期だよ。CPU使用率をやけに気にしてるけど、
MP向けだとスピンじゃないと話にならないことも多い。

83:35
09/09/24 14:21:36
>>82

(CASやスピンを用いた)lock-free単独による同期については、メニーコア、
あるいはその先(未来)にある超並列な世界であれば、並列システム全体から
見ると個々のコア(CPU)の無駄は無視できます。だから、その時代になれば
「lock-free単独による同期が常識」となっている可能性は十分に予測できます。
もしかすると、現在でも>>82が主張されているMP(?)向け用途、それに
HPC(High Preformance Computing)やCELLのプログラマにとっては、
既に「lock-free単独による同期は常識」なのかもしれませんね。

ただし、現在のPC向け汎用CPUはシングルコアかせいぜい4コアが主流です。
その世界では、いかに個々のコアを無駄無く使いつぶすかが、
性能設計上の大きな課題になります。ですから、現時点では、
「lock-free単独による同期は一般的ではない」、言い換えると、
一般アプリケーションにおいては「スリープなどと組み合わせない限り
(単独の)lock-freeでは同期は実現できない」と解釈しています。

論理的にはCASやスピンでも同期は実現可能である(立派な同期である)。ただし、
一般的な多くのケースにおいては、その方式は現実的ではないということです。
これもまた「できる/できない論争」の一種ですよね。

84:デフォルトの名無しさん
09/09/24 14:28:13
デュアルコアでさえスピンは使うって。

lock-free queueのcalleeが同期の機能を持ってるか、にこだわってるの?
callerが同期処理をしなきゃならない、だとしても、lock-freeで同期してることに
なると思うけど。そうじゃないなら、シーケンスロックはロックの機能を持たない
とかいう変な話になるぞ?
つーか、ノンブロッキング同期の一種だぞ、lock-freeもwait-freeも。

85:35
09/09/24 14:51:24
>>84

同じ「待ち」でも、「排他(ロック)」と「同期」は別のものです。

「排他」による待ちは一時的です。もしもそれが長時間継続するようであれば、
それは「設計が悪い」のです(一般にはバグとして扱う)。
それに対して「同期」の継続時間は不定です。
最も長いケースでは、システム全体が終了するまで「待ち」状態が継続します。

また、共有キューを用いた「同期」を実現するには「排他」も必要です。
ただし、だからといって「排他」だけでは「同期」は実現できません。

「排他(ロック)」と「同期」を区別して、考え直してみてください。

lock-freeには「排他」機能があります。ですから「デュアルコアでさえ
スピンを使う」ことはあります。でも、lock-freeを単独で「同期」に
用いるのは現実的ではないと言っています。

というか「できる/できない論争」は止めにしませんか?私はこれで降ります。

86:デフォルトの名無しさん
09/09/24 15:05:18
> 一般的な多くのケースにおいては、その方式は現実的ではないということです。

ここの認識が勘違いしてると思うけどなぁ。
まぁ降りるならどうぞ。

87:デフォルトの名無しさん
09/09/24 16:28:41
lock-free queueの話で同期の話が出てくる時点で何かおかしい気がしている
lock-free queueってのはこういうものだと認識しているのだけど…↓

マルチスレッドにおけるQueueのpushとpopの処理では、内部の変数の更新が衝突すること
によって破壊されてしまう場合があるため、何かしらの機構を備えておく必要がある。
mutex等による排他制御ではコンテキストスイッチが発生し、それは時間的にシビアな場面
においては非常に遅くなる場合がある。
そのためコンテキストスイッチさせないようにあの手この手を尽くして
(mutex等排他制御のためのプリミティブが使われていない)lock-freeなものを作る場合がある。
lock-free queueでは複数のスレッドからQueueに対してpush/popされても、内部でmutex等
による排他制御は行われず、コンテキストスイッチが起こらないため、複数スレッドから
の高速なデータのpush/popが期待できる。

↑何か間違ってる?
Queue(待ち行列)という特性を見るかぎり、Queueを使った同期ってのがどういうものか
イマイチ解らない。

88:デフォルトの名無しさん
09/09/24 16:51:14
if(v.empty()){/*待機コード*/}
int i=v.pop();

例えばこれも同期

89:デフォルトの名無しさん
09/09/24 16:52:09
ifじゃなくてwhileだった

90:デフォルトの名無しさん
09/09/24 17:23:43
>>88
それって、Queueを使うためにmutexやスピンロック等を使った同期であって、
Queueを使った同期ではないような…
もし仮にそのことをQueueを使った同期と言っているのであれば、それとlock-free queueとは
関連性薄くない?(べつにbool値のflagだとしても議論できるし)

もしかしてQueueとかもう話題的にあんまり関係なくて、
単純に、スピンロックやmutex等の排他制御、CASはそれぞれどういう時に便利ですか?
って議論だったりする?

91:デフォルトの名無しさん
09/09/24 17:47:00
>>88
empty()とpop()が別だから、複数スレッドだとrace conditionになるね。

92:デフォルトの名無しさん
09/09/24 18:03:19
どう見てもmutexもスピンロックも使ってないし、empty()じゃなくなった後に
empty()がtrueにならないことが保証されてるqueueなら競合もしないよ

93:デフォルトの名無しさん
09/09/24 18:08:41
お互いに勝手なコンテキストを想定して話すから、会話が成り立ってない。

94:デフォルトの名無しさん
09/09/24 18:13:27
・読み手/書き手は単数なのか複数なのか
・一般例なのか状況限定の例なのか
・empty()はロックしないことを保証しているか(lock-freeならしているだろうけど)

こういう重要な条件をお互いに伝える気も読み取る気も感じられない。

95:87
09/09/24 18:25:37
while (v.empty()){}
↑こういうコード(ある状態が真になるまでループする)がスピンロックなのかと思ってた。
>>92みると違うみたい?


96:としあき
09/09/24 18:34:00
> こういう重要な条件をお互いに伝える気も読み取る気も感じられない。


97:デフォルトの名無しさん
09/09/24 18:50:40
>>95
それロックじゃないでしょ

98:デフォルトの名無しさん
09/09/24 23:38:03
空気読まずに lock-free C++ vector の論文貼るね。既出ならメンゴ。
URLリンク(www.research.att.com)
2006 年、Bjarne Stroustrup も噛んでる。なかなか性能いいみたい。

99:35
09/09/25 02:21:30
>>87

lock-free queueを実装する視点であれば、その認識は間違っていないと思うよ。

>>90
>単純に、スピンロックやmutex等の排他制御、CASはそれぞれどういう時に便利ですか?
>って議論だったりする?

自分はlock-free queueを使う立場だから、そういう視点で>>81まで議論を続けてきました。
で、その後から議論が拗れてしまったわけですね。

何が原因かを考えました。自分は、(共有キューの競合による破壊を防ぐ為の)「排他」制御の為に
スピンを「使う」ことは「一般的である」けれど、キューが空の場合に「待つ」、いわゆる
「同期」の為にスピンを「使う」のは(汎用PC/CPUの世界では)「一般的ではない」という立場。

それに対して、いや、キューが空で「待つ」場合にも、スピンを「使う」のは(汎用PC/CPUの
世界であっても)「一般的である」というのが、相手の立場。

ある事柄に対して、それが「一般的である/ではない」という解釈は、一般常識論ですから、
それぞれの立場によって異なるのが当たり前です。そんな両者が納得できる結論を導くのは難しい。
だから、>>85では、これ以上議論を続けても不毛なので止めることを提案しました。

100:デフォルトの名無しさん
09/09/25 13:02:48
できません

できます

一般的じゃないからできないようなもんです

ハァ?

って流れに見えた

101:デフォルトの名無しさん
09/09/25 15:30:44
私はこれで降ります

何が原因かを考えました

提案しました

ワロタ

102:デフォルトの名無しさん
09/09/26 14:00:48
>>87
多分間違っていると思うよ

コンテキストスイッチは関係ない。
lock-free なキューのメリットは、lock-free でないキューより
(ロックしないから)アクセスの並列性が高まること。
もちろん競合するときには性能が落ちるけど、平均的には
性能向上が期待できる。

103:デフォルトの名無しさん
09/09/26 20:19:00
アクセスの並列性ってどういうこと?
それが高いと何がうれしいの?

104: ◆0uxK91AxII
09/09/26 20:34:29
こんなケースで、こういうlock-freeなのを実装したら、
これだけパフォーマンスが向上しました・
...みたいなのを挙げてみてほしい。

どうでも良いけど、jemallocでも、spinlockしているね。

105:デフォルトの名無しさん
09/09/26 21:38:58
>>103
ロックは重い処理だから、それなしにCAS等の手法で数十ステップで収まるloc-freeは
軽い(逐次実行時間が短い)ってことを言いたいんだろ。

ただ、コンテクストスイッチは関係ないと言い切っちゃうのは、もう......だなw

106:デフォルトの名無しさん
09/09/26 22:37:25
lock-freeの定義が各人の頭の中にしかないから1000までこの話題でも結論は出ない(キリッ

107:デフォルトの名無しさん
09/09/26 23:05:40
まず、スピンロックとlock-freeにおけるCASの違いは

スピンロックは、単純に同じ動作(CAS)を再試行する
lock-freeの実装では、単純に値を読み直す場合や全ての動作を最初からやり直す場合等いろいろあるが
とにかく、「同じ値で再度CASを実行する」ということはしない。

wait-freeは、上記の「CASの再実行」が起こらない、ということだから
言い直せば、retry-freeとでも言えるのかも知れない。

108:デフォルトの名無しさん
09/09/26 23:10:11
あと、上のほうで「CASを使わなくてもメモリバリアがあれば云々」という話があったようだが
CASが重いのは、CASに含まれるメモリバリア(バスロック)動作が重いのが理由なのだから
CASを無くしたからってメモリバリアが必要なら、たいしてメリットは無くなる。

もし、「メモリバリアも無くしてかつwait-freeな実装が可能」というなら話は別だが。

109:デフォルトの名無しさん
09/09/27 09:14:18
>>103
ちょっと古いけど、
URLリンク(www.ibm.com)
のスケーラビリティの問題あたりから下の部分はどう?

110:デフォルトの名無しさん
09/09/27 15:28:18
>>108
> CASが重いのは、CASに含まれるメモリバリア(バスロック)動作が重いのが理由なのだから
メモリバリアとバスロックは別の概念だぞ。
たとえばIA-64には、メモリバリア無しのCAS命令(ニーモニック:cmpxchg)と、
メモリバリア有りのCAS命令(cmpxchg.acq や cmpxchg.rel)がある。

そもそも、メモリバリア自体はそこまで重い操作じゃない。
特に、C++0xでの memory_order_acquire, memory_order_release に相当する
メモリバリアは、自身のスレッド内での順序づけを保証するだけなので、
他CPUとの通信を必要としないためコストもかなり小さい。
で、これまで話題になっているwait-freeなlinked queueなど、
多くのlock-free, wait-freeアルゴリズムの実装では、
この acquire, release 相当のメモリバリアで十分だ。


111:デフォルトの名無しさん
09/10/01 09:08:46
見よう見まねでスピンロック実装して動作テストしたら標準のCriticalSectionより劇おそだったのは苦い思い出:プライスレス(´・ω・`)

112:デフォルトの名無しさん
09/10/01 10:15:16
Win32のCriticalSectionの激速の理由は
プロセッサを判定して、可能ならばunlockにmovを使ってバスロックを避けているから

と俺は勝手に想像している。

113: ◆0uxK91AxII
09/10/01 18:03:15
push/popを必要最低限にして、
適宜pause(rep; nop)を入れれば良いだけ。

114:234
09/10/01 20:17:23
>>112
コンテキストスイッチが無いときはカーネルに入らずに、単にロックカウントをアップしてるだけだからだよ。


115:デフォルトの名無しさん
09/10/01 21:48:37
>>114
いやそんなの当たり前だし。

「単純なスピンロックより速い(>>111)」理由が何故か?だよ。論点は。

116:デフォルトの名無しさん
09/10/01 22:46:40
>>115
非コンテキストスイッチング時はアセンブラで10数命令しか実行して無いんだから速いよ。
それに>>111のコードを見なければなんともいえない。


117:デフォルトの名無しさん
09/10/01 23:01:29
だから、その命令の中に、lock xadd とかの重い命令があるんだよ。

118:デフォルトの名無しさん
09/10/01 23:10:26
コンテキストスイッチが無いから速い、とか
アセンブラで10数命令だから、とか

偉そうな態度の割に、底が浅すぎる。

119:デフォルトの名無しさん
09/10/02 00:06:49
お前も相当えらそうだが。

120:デフォルトの名無しさん
09/10/02 00:26:57
無知が知ったかぶって偉そうにしながら恥を晒してるのとは違うみたいだけど。

121:デフォルトの名無しさん
09/10/02 00:44:09
間違っているというだけで何が間違っているか書かないやつは大抵ハッタリだわな。

122:デフォルトの名無しさん
09/10/02 00:44:47
>>121
それ正解。

123:デフォルトの名無しさん
09/10/02 00:49:28
void __stdcall trylock(volatile int *spin) {
__asm { mov ecx, spin;
mov edx, 1;
xor eax, eax;
lock cmpxchg [ecx], edx;
}
}
void __stdcall unlock(volatile int *spin) {
__asm { mov ecx, spin;
xor edx, edx;
mov eax, 1;
lock cmpxchg [ecx], edx;
}
}
void __stdcall trylock_nlk(volatile int *spin) {
__asm { mov ecx, spin;
mov edx, 1;
xor eax, eax;
cmpxchg [ecx], edx;
}
}
void __stdcall unlock_nlk(volatile int *spin) {
__asm { mov ecx, spin;
xor edx, edx;
mov eax, 1;
cmpxchg [ecx], edx;
}
}
void __stdcall unlock_nbl(volatile int *spin) { *spin = 0; }

124:デフォルトの名無しさん
09/10/02 00:50:21
DWORD readtsc() {
DWORD v;
__asm {
rdtsc;
mov v, eax;
}
return v;
}
int main() {
const COUNT = 1000;
CRITICAL_SECTION cs;
InitializeCriticalSection(&cs);
volatile int spin = 0;

int st = readtsc();
for (int i = 0; i < COUNT; ++i) { EnterCriticalSection(&cs); LeaveCriticalSection(&cs); }
printf("%u clocks at %s\n", readtsc() - st, "CriticalSection");
st = readtsc();
for (int i = 0; i < COUNT; ++i) { trylock(&spin); unlock(&spin); }
printf("%u clocks at %s\n", readtsc() - st, "CAS");
st = readtsc();
for (int i = 0; i < COUNT; ++i) { trylock_nlk(&spin); unlock_nlk(&spin); }
printf("%u clocks at %s\n", readtsc() - st, "CAS(lockプリフィックス無し)");
st = readtsc();
for (int i = 0; i < COUNT; ++i) { trylock(&spin); unlock_nbl(&spin); }
printf("%u clocks at %s\n", readtsc() - st, "CAS(movでunlock)");
}

125:デフォルトの名無しさん
09/10/02 00:51:21
ほれ、ベンチ用意したぞ。
シングルスレッドで、ロック獲得が必ず成功する場合の数字のみ。
実際はカウンタ持ってるから単純なcmpxchgじゃなくxaddで正負と0を駆使して判定してるだろうし
ロックを獲得できなかった場合にブロックに移行する処理もあるだろうけどな。

まあ見難いが、面倒くさかったから
TABのインデントは見たい人が自分でやってくれ。

126:デフォルトの名無しさん
09/10/02 00:54:44
これでもまだ「コンテキストスイッチが」「命令数が」と言いたいなら
ご自由にどうぞ。

127:デフォルトの名無しさん
09/10/02 00:58:52

しかしお前がどのレス書いたやつで何を主張したいのかがわからん。

128:デフォルトの名無しさん
09/10/02 01:03:20
実行してみなきゃ結果の意味するところもわからんからね。
まあ俺は>>112>>115>>117とかだが。

関係ないが、stdcallとか、全然意味なかったな。
全部展開されてるし。
しかも、Enter/Leaveもレジスタにコピーされてレジスタ間接コールになってる。

129:128
09/10/02 01:04:01
>>123-124が俺な。

130:128
09/10/02 01:27:59
まあ一応、俺の手元での数字を出しとく。
rdtscで計ってるので、別プロセスに割り込まれない限り
何回やっても似たような数字になる。

18065 clocks at CriticalSection
39098 clocks at CAS
13700 clocks at CAS(lockプリフィックス無し)
19025 clocks at CAS(movでunlock)

1番上が、単純にCriticalSectionをEnter/Leaveしたもの。
次が、「教科書通り」のCAS(lock+cmpxchg)を使ったスピンの取得と解放。
おそらく、>>111もこれに似たコード(取れない時のループは無し)を書いたと思われる。
3番目は、上のコードから、バスロックを除いたもの。バスロックのコストを示すため。
4番目が、>>112に述べた、unlock時のバスロックを避けるようにしたもの。

結論としては、>>112の推測が確信に変わっただけ。

131: ◆0uxK91AxII
09/10/02 11:18:35
spinlockの話題>>111
が、CASにすり変わっている件について。

132:デフォルトの名無しさん
09/10/02 12:33:54
「教科書通りのスピンロック」って、普通は
xchg (test-and-set)でロックを取って、movでアンロックじゃねーの?
それとも最近の教科書は test-and-set より先に
compare-and-swap を教えるのかな?

133:デフォルトの名無しさん
09/10/02 13:15:17
一般のプロセッサでxchgが1バスサイクルで実行される保証なんて無い。
というより、普通は読みと書きになる。(x86が特殊なだけ)
だから、ロックを取得するにはCASが必要。

134:デフォルトの名無しさん
09/10/02 13:17:13
あ、ごめん
TASならば確かにCASである必要は無いね。

135:デフォルトの名無しさん
09/10/02 13:22:36
だけど、「アンロックがmovが普通」は違う。

理由は
Wikipedia項目リンク
のように、
movだと、直前のクリティカルな部分への書き込みが他のプロセッサに伝わる前に
アンロック処理のmovの書き込みが他のプロセッサに伝わる可能性があるため。

136:デフォルトの名無しさん
09/10/02 13:52:10
>>135
それはメモリバリアの問題であって、movかCASかは関係ない。
mov命令がreleaseメモリバリア効果を持っていればそれで十分だし、
逆に>110で挙げたようなメモリバリア無しCAS命令では不十分。

137: ◆0uxK91AxII
09/10/02 13:54:13
>>135
それはspinlockを使う側が考慮する問題であって、
作る側は無視して良い。

138: ◆0uxK91AxII
09/10/02 13:59:49
W2kSP4, Athlon 64 X2 3800+, VC6SP6+PP5, 最適化無し
50239 clocks at CriticalSection
49180 clocks at CAS
21132 clocks at CAS(lockプリフィックス無し)
32103 clocks at CAS(movでunlock)

139:デフォルトの名無しさん
09/10/02 14:24:08
>>136
それがメモリバリアの問題だっていう、そんなことわかってるよ。
そして、「一般的なmov」はメモリバリアの機能など持っていない事
さらに、「(次に書く)このスレで"一般に"用いられるCASという用語」はメモリバリアを持っているもね。

もちろん、CASというのがメモリバリアとは直接は関係ないってことだって充分知ってるよ。
(そうでなければ、lockなしのcmpxchgなんてもの出すわけ無いだろ)
だけどこのスレで一般的にCASと言ったら
「アトミック操作で用いる事が可能なCAS」のことが普通だろうに。

140:デフォルトの名無しさん
09/10/02 14:28:11
「一般的なmov」つまり、普通のロード/ストア操作はメモリバリアを持っていないのだから
普通のスピンロックの実装では、アンロック処理に
movではなくメモリバリアを持ったTASやCASを使う。
(それらはロック獲得処理の段階で存在が示されている)

だから「普通はmovでアンロック」などということは有りえない。

141:デフォルトの名無しさん
09/10/02 14:37:59
>>140は「教科書では」ね。

142:デフォルトの名無しさん
09/10/02 14:53:16
Windows Vista 64bit SP1, Core2DuoE6750, Microsoft Visual Studio 2008(VC Version 9.0.21022.8 RTM)

/O2 /Ob2 /Oi /Ot (実行速度で最適化、インライン関数は展開可能な関数すべて展開)
101192 clocks at CriticalSection
67904 clocks at CAS
20424 clocks at CAS(lockプリフィックス無し)
88688 clocks at CAS(movでunlock)

/Od /Ob1(最適化なし、インライン関数は展開しない)
108568 clocks at CriticalSection
99976 clocks at CAS
24184 clocks at CAS(lockプリフィックス無し)
65280 clocks at CAS(movでunlock)

>>130の結果が謎すぎる

143:デフォルトの名無しさん
09/10/02 15:17:56
>>139
アトミック性とメモリバリアは別の概念だぞ。
CASがアトミックなのは当たり前であり、俺もそんなことに
文句をつけているわけじゃない。

x86におけるlockプレフィックスのないcmpxchgは
SMP環境ではアトミック性が保証されないから
(正しい意味での)CASとは言えない。
でも、>110で挙げたのは「アトミック性は保証されているが
メモリバリア効果を持たないCAS」だ。

CASとは「あるメモリ位置に対する内容の取得・比較から代入までが
アトミックに行える操作」であり、メモリバリア効果、つまり
「前後の命令との間でリオーダーを行わないという保証」は必須ではないと
俺は言っている。
# 実際に、C++0xのatomicライブラリではそのように定義されているし。

「普通のロード/ストア命令はメモリバリアを持たない」と言うのなら、
メモリバリアを持つロード/ストア命令を定義して、それを使えばいい。
何故わざわざCASやTASのような複雑な操作を持ち出す必要がある?

ちなみに、x86のmov命令は(初期のバグ持ちプロセッサを除いて)
デフォルトでreleaseメモリバリア効果を持っているぞ。

144:デフォルトの名無しさん
09/10/02 15:36:13
はいはいごめんよ。
全部俺が悪かったよ。

145:デフォルトの名無しさん
09/10/03 09:36:48
URLリンク(d.hatena.ne.jp)

ここが勉強になった。

146:デフォルトの名無しさん
09/10/03 10:16:52
ちらっと見ただけなんだけど、「volatile つけた変数に排他性は無いよ」
ってことをグダグダ言ってるみたいだけど、そんなの当たり前では?

都市伝説もくそもねーよ

147:デフォルトの名無しさん
09/10/03 11:06:13
acquire/releaseバリヤって、
「そのスレッドでのメモリアクセスについて」限定?
↑のスライドだと前後の命令を・・・となってるけど

148:デフォルトの名無しさん
09/10/03 11:36:54
当たり前よ
っつかどういう意味で聞いてる?


149:デフォルトの名無しさん
09/10/03 11:37:10
菊池バリヤー!

150:デフォルトの名無しさん
09/10/03 16:40:11
「バリア」って概念には
「メモリアクセスがコーダーが記述した”順”に実行されることが
保証される」っていう以上のものは含まれていない(例えばインク
リメント操作がアトミックになることまでは保証されない)と認識し
ているのですが。当たってます?
ネットに散らばっている情報にはブレがあると思えるし、正直、
勉強不足ではっきりと分からないところがあるので質問します。


151:デフォルトの名無しさん
09/10/03 18:09:38
>>150
それで正しい。
ちなみに、マルチスレッドの世界には「バリア同期」っていう全然別のものもあるので、
メモリバリアのことは「メモリフェンス」と呼ぶようにした方がいい。

152:デフォルトの名無しさん
09/10/03 19:15:56
>>151
ありがとうございます。頭の中がすっきりしました。

153: ◆0uxK91AxII
09/10/03 21:22:33
どうでも良い事だけど。

spinlockを奪い合った場合、
先に取ろうとした方が取れず、
後から取ろうとした方が取れたとしても、
動作としては正しいんだよね。

154:デフォルトの名無しさん
09/10/03 21:37:43
spinlockはアンフェアだからそれで正しいね。


155:デフォルトの名無しさん
09/10/03 22:29:57
>spinlockはアンフェアだからそれで正しいね。
それは答えになってるのか??


156:デフォルトの名無しさん
09/10/03 23:21:32
間違いではない=正しい
という論理がわからないのか?

どうしょうーもねーな

157:デフォルトの名無しさん
09/10/03 23:32:43
正しいのか?って言ってんじゃなくて
答えになってるのか?
って言ってんだけど。


158:デフォルトの名無しさん
09/10/04 00:51:01
答えにはなっているように見える。「正しいのか?」という問いに「正しい」と答えている。
その答えが正しいのかどうかは別の話。

159:デフォルトの名無しさん
09/10/04 03:29:21
Wikipedia項目リンク

160:デフォルトの名無しさん
09/10/05 13:09:01
>>155
説明になっているかどうかはともかく
答えにはなっていると思うんだが。

161:デフォルトの名無しさん
09/10/13 02:20:13
火元の人
 やり方が理解できない質問者
 俺に分からないならこのスレにも理解できる奴いないんじゃね、とか思っていて、
 それが態度にも滲み出ている

煽る人
 分かってるつもりだけど分かってないで煽り続ける
 こいつを見た火元は「やっぱり分かってる奴いないんじゃないか」と思いこむ

住人タイプA
 一目で分かるがお前の態度が気に入らないしコード示すのマンドクセ
 つーかこの説明で分かれボユゲ

住人タイプB
 みんな何言ってんだかわかんね

ちょっと違うけどこのパターンに似てる

162:デフォルトの名無しさん
09/10/14 09:48:32
posix準拠のオーソドックスなやり方しかしない俺にはこのスレは不要なようだ
おまえら何言ってるかわかんねぇーしw

163:デフォルトの名無しさん
09/10/14 10:36:30
>>162
自分からPOSIXスレッドとかに関連したネタをふればいいんじゃないかな?

まあ正直なところ、ここは相談室スレなんだから、あまりにもハードウェア寄りな専門知識が
必要な話題については、できれば「並列化について語る」スレで熱く語ってくれって感じはしてる。
あっちはハード(マルチプロセッサ/マルチコア)全然オケーなスレなんだから。

164:デフォルトの名無しさん
09/10/14 13:09:43
単に自分の付いていけないレベルの話題を締め出したいだけに見える

165:デフォルトの名無しさん
09/10/14 13:35:03
ということにしたいだけにも見える

166:デフォルトの名無しさん
09/10/14 21:17:55
つーか俺はposix準拠な世界で生きてきたので。
おまえらよくposix非準拠な話題で盛り上がれるなーw

167:デフォルトの名無しさん
09/10/14 22:48:54
>>166
CASやメモリバリアなどはpthreadライブラリの実装者にとっても
必須の知識だよ。

168:デフォルトの名無しさん
09/10/14 23:10:22
>>167
利用者にとっては?

169:デフォルトの名無しさん
09/10/15 03:21:14
POSIX厨としか言いようがない

170:デフォルトの名無しさん
09/10/15 08:47:16
>>169
POSIX使うのが普通じゃないの?

171:デフォルトの名無しさん
09/10/15 13:13:35
pthreadにはアトミック操作が定義されてないから、
単なるカウンタのインクリメントでも
いちいちロックしなきゃならんのが嫌だ。

172:デフォルトの名無しさん
09/10/16 00:37:47
なんでPOSIXで厨なんだよ(´・ω・`)

173:デフォルトの名無しさん
09/10/16 02:28:34
POSIXスレッド以外の話題ってだけで叩くなら完全に厨だろ

174:デフォルトの名無しさん
09/10/16 06:51:32
他人を厨と決めつける人が厨に見える


175:デフォルトの名無しさん
09/10/16 08:03:36
何でも鸚鵡返しすれば反論になると思ってるだろ

176:デフォルトの名無しさん
09/10/16 08:04:58
baka

177:デフォルトの名無しさん
09/10/16 08:09:28
pthread地獄 part 2
スレリンク(unix板)

ここへ行けばいいのに

178:デフォルトの名無しさん
09/10/17 03:19:26
          /\              ┌┐            ┌┐       ___ ___
        / __ \       /\  ..||..  /\       ||    ___ \\ \
      / / .\ \     \  \ .||. /  / ┌─┘└─、\\  ̄  ̄
    / /     .\ \     \/ .||. \/   └─┐┌─ 、| |__|
  / / ┌─┐.\ \  ┌──┘└──┐      .||  ||
 ..\/   └┐┌┘  .\/ └──┐┌──┘     / /  ||
        ┌┘└┐          /\ .||. /\      / /   / /
        └┐┌┘        /  / .||. \  \   / /   / /
      ┌─┘└─┐     \/  ..||..  \/   \/    / /
      └──┘          └┘              \/

                                           ....、
....................--------、,           i~゙7   r‐ッ    !゙゙.!       ! !
: !――;;;;;;''''''''ゝ ,,ノ゛    ._   / ./   .,! .,!    ! !  .,..............! ヽ..........-、
      | |./ /      .l、,`''-./ ./    ! !    | |   ―ーッ .iー''''''''i |
      | l'-‐゛        `゙ッ  .ゝ、   .| |    | ,!      ./ ./   ! !
     ../ .,!             /.,r'"\,/  .!ー′   ./ .,!     . / ./    | │
    .,./ ./         ,..‐" /            . / /     ./../     ./ .l゙
  .r'"./           ゝ/゛          : ,,-'゛./    .〈 /    .'|,゙,゙,,,, "
   .`゛                        ゙'''"

179:デフォルトの名無しさん
09/10/20 15:39:31
その “全米” はグアム島を含むのでしょうか。

180:デフォルトの名無しさん
09/10/20 19:08:01
グアム、どうなんだろ。州に昇格すればいいのに。まあ、しないだろうけど。

181:デフォルトの名無しさん
09/11/03 00:02:53
スレッドを終了させるときは_endthreadexじゃなく
そのままreturnでもいいのか?スタックの開放されない?

182: ◆0uxK91AxII
09/11/03 00:28:01
良い。
mallocで取ってきた領域をfreeしなくて良いのと同じくらいに。

スタックとやらは、_endthreadexとは無関係。

183:デフォルトの名無しさん
09/11/03 00:59:57
freeしろよ

184:デフォルトの名無しさん
09/11/03 01:16:04
スレッドに強くないのに書き込んでみる。

URLリンク(msdn.microsoft.com)(VS.80).aspx
>ただし _endthread または _endthreadex は、_beginthread や _beginthreadex の
>パラメータとして渡されたルーチンからスレッドが戻ると自動的に呼び出されます。

ってことで、returnすれば問題ないかと。
どちらかというと

>_endthread と _endthreadex によって、C++ デストラクタはスレッドで保留状態になり、呼び出されません

なので、呼ばないほうが好ましいような。

185: ◆0uxK91AxII
09/11/03 01:52:01
182は無かった事にしてください。
んゆ。

186:184
09/11/03 14:42:55
スレッドに強い人に補強して欲しいのだけど、それとも184の認識で問題なし?

187: ◆0uxK91AxII
09/11/03 17:34:11
Microsoft Visual Studio\VC98\CRT\SRC\THREADEX.C

んゆ。

188:デフォルトの名無しさん
09/11/03 17:55:09
問題なし

189:デフォルトの名無しさん
09/11/03 22:08:15
スレッド識別子って何なんだ?
何に使うの?

190:デフォルトの名無しさん
09/11/03 22:25:48
殺したり、止めたり。

191:デフォルトの名無しさん
09/11/04 21:43:06
他スレッドの変数の中身知ることってできないかな?

192:デフォルトの名無しさん
09/11/04 21:55:11
メモリ空間は共有しているので、アドレスがわかれば普通に参照できる。

193:デフォルトの名無しさん
09/11/05 12:32:06
win32のインターロックをクリティカルセクションと
同じように使ったら早くて驚いた。

両者の内部的な違い・利点・欠点てなんですかね?

194:デフォルトの名無しさん
09/11/05 14:06:45
そもそも用途が違うんじゃない?
インターロックは変数1個ぶんの更新しかできないでしょ?

インターロックを使ってクリティカルセクションと同様のものを作ることはできるだろうし、
クリティカルセクションを使ってインターロックと同様のものを作ることもできるだろうけど、
そういう話?

195:デフォルトの名無しさん
09/11/05 14:31:15
インターロック一発で出来ることならインターロックで。


196:デフォルトの名無しさん
09/11/05 14:54:32
win32のクリティカルセクションは衝突しなければインターロックと同じくらい早いんだなこれが

197:デフォルトの名無しさん
09/11/05 16:01:33
いや倍くらいは遅いだろう。


198:デフォルトの名無しさん
09/11/05 16:15:02
んだ。インターロックで済むならそれが数倍早い。

199:193
09/11/05 19:29:23
今以下のクラスでクリティカルセクションと同じように扱ってテストしてるんだ。
class InterLock
{
private:
LONG m_Flag;
public:
void Enter()
{
while(InterlockedCompareExchange(&m_Flag,1,0)) Sleep(0);
}
void Leave()
{
InterlockedCompareExchange(&m_Flag,0,1);
}
public:
InterLock()
{
m_Flag = 0;
}
virtual ~InterLock()
{
}
};

200:193
09/11/05 19:30:08
こっちはクリティカルセクション晩
class CriticalSection
{
private:
CRITICAL_SECTION cs;
public:
void Enter()
{
EnterCriticalSection(&cs);
}
void Leave()
{
LeaveCriticalSection(&cs);
}
public:
CriticalSection()
{
InitializeCriticalSection(&cs);
}
virtual ~CriticalSection()
{
DeleteCriticalSection(&cs);
}
};

201:193
09/11/05 19:43:57
//グローバル変数
ロッククラス g_Lock;
int g_i = 0;

// 三つのスレッドで以下を走らせる
void Run()
{
for(int i=0; i<10000000; i++)
{
g_Lock.Enter();
g_i++;
g_Lock.Leave();
}
}

int main()
{
//3つのスレッドでRun()を走らせ、スレッド終了まで待機
(...省略)
cout << g_i << endl;
cout << time.result() << endl;
return 0;
}

結果
クリティカルセクション 35秒 g_i = 30000000
インターロック 5.5秒 g_i = 30000000
ロッククラス無し 0.16秒 g_i = 21203536(整合性無し)

環境 OS:win xp CPU:core2duo1.8G メモリ:3G

202:デフォルトの名無しさん
09/11/05 20:42:07
ソースまともに見てないけど、CSがもしインライン化されないなら性能的には勝てない
だろうしなぁ
まぁ、asm読めば全て分かるだろうけど

203: ◆0uxK91AxII
09/11/05 23:23:50
TryEnterCriticalSection ~ Sleepだとどうなるの、っと。
threadをCPUと1:1にbindしたらどうなるの、っと。
timesliceを変えたらどうなるの、っと。

結果は書かない方が良い。

204:193
09/11/06 07:01:38
>TryEnterCriticalSection ~ Sleepだとどうなるの、っと。
これだけやってみた。
上記のテストだとインターロックとの差は0.5秒内、
つまりほとんど差がなくなった

205:デフォルトの名無しさん
09/11/06 13:00:12
プロセッサ数が2以上ならSpinWaitにしたらどうなる?
あとインターロックのIncrementでダイレクトアップデートにしたらどうなる?


206: ◆0uxK91AxII
09/11/06 20:26:47
違うネタだけど。
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#include <stdlib.h>
#define THREADS 64
#define LOOPS 123456789
struct SData { LARGE_INTEGER m_cntBegin; LARGE_INTEGER m_cntEnd;};
DWORD WINAPI thread(LPVOID pArg);
int __cdecl cmpForSort(const void *pArg0, const void *pArg1);
int _tmain()
{
int i; HANDLE ahThread[THREADS]; SData aData[THREADS];
LARGE_INTEGER diff;
for (i=0; i<THREADS; i++)
ahThread[i] = CreateThread(NULL, 0, thread, &aData[i], 0, NULL);
WaitForMultipleObjects(THREADS, ahThread, TRUE, INFINITE);
qsort(aData, THREADS, sizeof SData, cmpForSort);
for (i=0; i<THREADS; i++)
{
CloseHandle(ahThread[i]);
diff.QuadPart = 0<i? aData[i].m_cntBegin.QuadPart - aData[i-1].m_cntBegin.QuadPart: 0;
_tprintf(_T("thread: %d, diffBegin: %I64d, clock: %I64d\n"), i, diff.QuadPart, aData[i].m_cntEnd.QuadPart-aData[i].m_cntBegin.QuadPart);
}
return 0;
}

207: ◆0uxK91AxII
09/11/06 20:28:49
DWORD WINAPI thread(LPVOID pArg)
{
SData *pData; DWORD value; float sum;
pData = (SData *)pArg;
QueryPerformanceCounter(&pData->m_cntBegin);
__asm
{
mov ecx, LOOPS
fldz
LOOP_:
fadd QWORD PTR value
dec ecx
jnz LOOP_
fstp DWORD PTR sum
}
QueryPerformanceCounter(&pData->m_cntEnd);
return 0;
}
int __cdecl cmpForSort(const void *pArg0, const void *pArg1)
{
LARGE_INTEGER diff;
diff.QuadPart = ((SData *)pArg0)->m_cntBegin.QuadPart - ((SData *)pArg1)->m_cntBegin.QuadPart;
if (0 > diff.QuadPart) return -1;
if (0 < diff.QuadPart) return 1;
return 0;
}

208: ◆0uxK91AxII
09/11/06 20:37:44
同じ処理なのに所要時間がブレるとか、
先に開始したthreadよりも、後から開始した方が早く処理を終えるとか。
そういうのが起こりうる。

computer gameでmulti threadの利用に消極的な理由の一つだと思う。

209:193
09/11/06 23:12:33
>>205
>インターロックのIncrementでダイレクトアップデートにしたらどうなる?
1.3秒だった

>SpinWait
これC#じゃん

210:デフォルトの名無しさん
09/11/07 01:40:37
スピン待機はC#限定じゃなく一般的な概念だ

211:デフォルトの名無しさん
09/11/07 09:40:03
スピンすると余計遅くなりそうだな。
一般的な使用状況に比べて処理と競合がタイトすぎるせいかな多分。


212:デフォルトの名無しさん
09/11/07 09:45:49
ああつまり3スレッド同時じゃなくて1スレッドで3回繰り返した方が速いとかっていう状態ね。


213:デフォルトの名無しさん
09/11/07 17:33:40
あーいやいや、これだとちょっと書き方がおかしいな…まあいいや


214:193
09/11/07 19:49:07
スピンロックは信頼性がないという話を聞いたような。

さて上記のベンチですが、1スレッドで3回繰り返したほうがずっと早いです。
衝突したときに別の処理をせずに待つ場合はシングルスレッドにした方がいいかも。


215:デフォルトの名無しさん
09/11/07 20:02:47
スピンロックに信頼性が無かったらどうすんだよw
全然仕組みとか分かってなくて使ってる匂いがぷんぷんするな

216:デフォルトの名無しさん
09/11/07 20:03:53
スピンロックとスピンウェイトは基本的に別物です。

217:デフォルトの名無しさん
09/11/08 00:12:02
それと信頼性に何の関係が?


218:デフォルトの名無しさん
09/11/08 02:55:49
スピン待ちの話をされてスピンロックどうこうと返すのがおかしい

219:デフォルトの名無しさん
09/11/08 10:06:21
上の人じゃないけど、スピンロックはスピンウエイトを使ってやってるかとおもてたよ(´・ω・`)

220: ◆0uxK91AxII
09/11/08 12:45:22
spinlockでlockできる保証は無いね。
偶然上手く動いているだけ。

221:デフォルトの名無しさん
09/11/09 01:48:53
◆0uxK91AxIIで検索したら、NGしてもいいくらいトンチンカンな奴だな

222:デフォルトの名無しさん
09/11/10 14:27:27
トリップ付けるような奴だもの。

223:デフォルトの名無しさん
09/11/10 20:06:21
トンチンカンなんて久々に見た
おやつあげないわよ


224:デフォルトの名無しさん
09/11/11 09:14:41
抜作先生の方がまだ新しいな。

225:デフォルトの名無しさん
09/12/15 00:01:41
マルチスレッド対応の基数木のアルゴリズムって
どうやって記述すればいいのでしょうか?

CかC++で探しています。

226:デフォルトの名無しさん
09/12/22 22:31:16
読み込みと書き込みが1スレッドずつの場合でもメモリ破壊って起きるのでしょうか?

たとえば、ある変数をメインスレッドで読み込み続け、
複数のサブスレッドで、クリティカルセクションを用い、書き込むといった場合です

227:デフォルトの名無しさん
09/12/22 22:39:31
>>226
とりあえず破壊読み出しメモリだと死ぬよね。

228:デフォルトの名無しさん
09/12/22 23:29:29
>>226
まずメモリ破壊を定義してもらおうか


229:デフォルトの名無しさん
09/12/23 01:41:11
パソコンのネジ外して開けると見えてくるメモリの部分をハンマーで叩く

230:デフォルトの名無しさん
09/12/23 01:42:27
ハードウェア的な話題もするんか

231:デフォルトの名無しさん
09/12/23 02:21:03
宇宙線による確率的なビット反転は防ぎようがない

232:226
09/12/23 10:10:00
データが飛ぶという意味でのメモリ破壊です
ハード的にどのように動作しているのか分からないのですが
同アドレスに同時にアクセスされることによってメモリ破壊が起きるのでしょうか?

233:デフォルトの名無しさん
09/12/23 10:20:05
書き込みをクリティカルセクションで同期して、クリティカルセクションを抜けたところで可視性が保証されたとしても、
読む方が書き込み中にその変数を見る可能性があるなら、少なくとも意図しない値を読む可能性はあるんじゃない?
(+不変な変数見てると思われるかもね)

要求次第だけど、
この手のポーリングするやつは、次に読めればいいからその瞬間のスナップショットで十分だと思うので、
Atomicな操作用のAPI使うとか、書き込みがAtomicであることが保証されるならvolatileだけでもいいかも。

その変数の読み書きだけ同期とっても、読んでる間の書き込みは防げても、
読み込みが終わってクリティカルセクション抜けたあと、それで処理しようと思ったら
もう書き換わってることもあるし。
読んだ値の処理が終わるまで書き込ませないなら、話は別だけど。

234:デフォルトの名無しさん
09/12/23 11:15:37
昔使ったタイマ LSI でラッチ→lo-read→hi-readって
いう約束ごとのあるやつがあったな。hi-readでラッチ
が外れる奴。word-read 命令が使えるかどうかは CPU
次第。

235:デフォルトの名無しさん
09/12/23 12:47:17
>>226
ハードや操作による。
つーか、まずは「アトミックな操作」という概念をどっかで調べとけ。

例えば、x86のCPUなんかだと、どういう操作がアトミックかはIntelが規定している。
アトミックな書き込みなら、別のコアからの読み込みが割り込む可能性は無い。逆に
アトミックでない書き込みなら、例えば半分くらい書き込んだところで別のコアが
読み込む可能性があるということ。
x86なら、厳密な規定はIntelの英語版サイトに落ちてる。32bitアラインドなreadや
writeは確実にアトミックだ。相当古いx86以外はキャッシュアラインドなら大丈夫。
read-modify-writeはLOCKプリフィクスが無い限りアトミックではないが、xchg
命令はLOCK#が自動的にアサートされるのでアトミックだ。
まぁ、アセンブラを直接叩くんじゃなければ、イントリンシック命令を調べておけば
十分だが、その裏でどういうCPUの動きをしているかは理解しといた方がいい。

つーか、低水準の話と高水準の話で全然違いすぎるんだよな。俺はどっちの話でも
構わんけど、分けた方がいいのか?

236:226
09/12/23 12:53:08
ありがとうございます
もっと勉強します

237:デフォルトの名無しさん
09/12/23 13:31:19
>>232
そんな事は起きないようにハードウェアが作られてる
物理的なメモリへのアクセス経路は1個しかないから、同じアドレスに同時にアクセス
なんて事は出来ない

命令が書いた順に実行されるかとか、他のコアやスレッド云々は >>235 の通り


次ページ
最新レス表示
スレッドの検索
類似スレ一覧
話題のニュース
おまかせリスト
▼オプションを表示
暇つぶし2ch

5395日前に更新/113 KB
担当:undef