启动顺序是连续的,因为创建调用按照它们写入的顺序发生。
但是,无论出于何种原因,调度程序都没有按照您希望的顺序调度新启动的线程。如果顺序很重要,也许线程不是您想要的?线程的一大优势是它们并不总是按顺序安排!
如果您真的想要,尽管您可以使用同步原语(例如一系列互斥锁或 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);
这样,当创建线程时,您并不关心实际上哪个线程有机会首先运行。