質問
私は現在POSIXスレッドについて学んでいますが、これはマルチスレッドに関する一般的な質問であると思います。私が取り組んでいる本から、競合状態を示すこの例があります:
void *thread_main(void *thread_number) {
printf("In thread number %d.\n", *(int *)thread_number);
}
void main() {
int i = 0;
pthread_t thread;
for( i = 0; i < 10; i++ ) {
printf("Creating thread %d.\n");
pthread_create(&thread, 0, thread_main, &i);
printf("Created thread %d.\n");
}
}
これについて理解していないことがいくつかあります。まず、「スレッド番号5で」スレッド番号5にあるはずがないにもかかわらず、何度も印刷されます。本では、スレッド8が何度も印刷される例を示しています。また、 *(int *)thread_number
と書かれている部分もわかりません。これを単にthread_numberに変更しようとしましたが、それは何度も何度も奇妙な数字を与えてくれました。
この本は実際にこれを説明していません。誰かがここで何が起こっているのか明確に説明してもらえますか?次のようなものが印刷されない理由がわかりません:
> Creating thread 1.
> In thread number 1.
> Created thread 1.
> Creating thread 2.
> In thread number 2.
> Created thread 2.
マルチスレッドであるため、「スレッド番号xで」ということを知っています。一部は異なる時間に来るでしょうが、なぜ「スレッド番号xに」が正確に10でないのか、私には本当に分かりません。作成したスレッドごとに1行で!
〜desi
解決
まず、*(int *)thread_numberはポインターです-thread_numberを取得したばかりのとき、「ストレンジ番号」は main 関数からの「i」へのポインターアドレスでした(そして、間違っています。プログラムの1回の実行ですべて同じ番号である必要があります(したがって、10個のスレッドのそれぞれが同じ「スレッド番号[番号]」である必要があります)。
これらは意味のある繰り返し5のポインタである-各スレッドは main 関数から同じ基になるiで動作していたことを理解する必要があります-新しいスレッドごとにコピーされていません、したがって、 main 関数でiがインクリメントされたとき、それは thread_main 関数のthread_numberに反映されました。
最後のパズルのピースは、各新しいスレッドのセットアップ時間とコンテキスト切り替え(実際に実行されているスレッドの変更)がすぐに行われないことです。したがって、あなたの場合、forループは新しく作成されたスレッドの5回前に実行されます実際に実行され(本の場合、forループはコンテキスト切り替えの8回前に実行されます)、各スレッドは同じ基になるi値(現在は5)を参照します。
他のヒント
作成された10個のスレッドのいずれかが実行される前に、forループが10回繰り返される可能性があります。その場合、 * thread_number
の値は、スレッドごとに10になります(単一の値を持つ単一のメモリ位置へのポインタであるため)。
i
へのポインターを pthread_create
に渡さない場合、 int
の値はアドレスとして扱われます、したがって、 thread_main
でそれを間接参照すると、任意のメモリ位置にアクセスしていることになり、その内容はおそらく未定義です。その場合、セグメンテーション違反ではないことは幸運です。
各スレッドで * thread_number
の正しい値を確認するには、 int
を呼び出してから int code> pthread_create
に、次のように i
の現在の値を割り当てます。
for( i = 0; i < 10; i++ ) {
int *thread_count = malloc(sizeof(int));
*thread_count = i;
printf("Creating thread %d.\n", i);
pthread_create(&thread, 0, thread_main, thread_count);
printf("Created thread %d.\n", i);
}
もちろん、次のように、スレッドが終了したらメモリを free
する必要があります:
void *thread_main(void *thread_number) {
printf("In thread number %d.\n", *(int *)thread_number);
free(thread_numbr);
}
まず、競合状態は悪いことです。このプログラムは期待どおりに動作しないはずです 。競合状態とは、プログラムが中断するように設計されていることを意味します。
この場合、すべてのスレッドが変数 i
を共有しているように見えます。単一の共有変数への参照を渡し、スケジュールされたときに報告しようとします。