起動順序はシーケンシャルであり、作成呼び出しは書き込まれた順序で行われます。
ただし、スケジューラーは、何らかの理由で、新しく起動されたスレッドを希望の順序でスケジュールしていません。順序が重要な場合、おそらくスレッドはあなたが望むものではありませんか?スレッドの大きな利点は、スレッドが常に順番にスケジュールされるとは限らないことです。
本当に必要な場合は、同期プリミティブ(一連のミューテックス、またはcondvarなど)を使用して、特定のポイントまでが予測可能な順序で発生するようにすることができますが、それ以降は、順序はまだ気まぐれになりますスケジューラー。例として、このコードは、各スレッドが作成された順序でIDを出力することを保証します。
#include <pthread.h>
#include <stdio.h>
static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
void sync_threads(const int num, int *cur) {
pthread_mutex_lock(&mut);
while (*cur != num) {
pthread_cond_wait(&cond, &mut);
}
// Do work that must happen in order here:
printf("Thread: %d\n", num);
++*cur;
pthread_mutex_unlock(&mut);
pthread_cond_broadcast(&cond);
}
static int num = 1;
void *thread1(void *d) {
sync_threads(1,&num);
while (1); // Rest of work happens whenever
return NULL;
}
void *thread2(void *d) {
sync_threads(2,&num);
while (1);
return NULL;
}
void *thread3(void *d) {
sync_threads(3,&num);
while (1);
return NULL;
}
void *thread4(void *d) {
sync_threads(4,&num);
while (1);
return NULL;
}
int main() {
pthread_t t1,t2,t3,t4;
pthread_create(&t1, NULL, thread1, NULL);
pthread_create(&t2, NULL, thread2, NULL);
pthread_create(&t3, NULL, thread3, NULL);
pthread_create(&t4, NULL, thread4, NULL);
while(1) {
// some work
}
}
私はwhile(1);
実際に起こっている作業をシミュレートするために使用しました。これは、「現在の」スレッドを保護するミューテックス、つまり初期化の順序と、スリープ/ウェイクアップを可能にするcondvarを使用して行われます。すべてのスレッドにブロードキャストし、スレッドは次にどのスレッドが稼働しているかを確認します。ブロードキャストをスキップするシステムとして設計することもできますが、それは比較的わずかな利益で物事を複雑にします。
他のポイントで必要に応じて同期を追加することもできますが、同期を多くするほど、そもそもスレッドを持つことのポイントが少なくなります。
理想的には、予測可能な順序で物事を行う必要がある場合は、スレッドがスポーンする直後ではなく、スレッドをスポーンする前に実行する必要があります。例:
fixed_init_for_thread1();
fixed_init_for_thread2();
fixed_init_for_thread3();
fixed_init_for_thread4();
pthread_create(thread1,NULL,thread_func1,NULL);
pthread_create(thread2,NULL,thread_func2,NULL);
pthread_create(thread3,NULL,thread_func3,NULL);
pthread_create(thread4,NULL,thread_func4,NULL);
そのため、スレッドが作成されるまでに、どちらが実際に最初に実行される機会が与えられるかは気になりません。