【问题标题】:multithread launching order多线程启动顺序
【发布时间】:2012-05-16 10:36:22
【问题描述】:

我有 4 个线程来创建 thread1、thread2、thread3 和 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);

在debug中看,启动线程的顺序和源码中定义的不一样。 是否有解决方案可以按照我可以定义的顺序启动线程?

【问题讨论】:

  • @Jay - 我想我倾向于同意它们是重复的,这个是对前一个的轻微概括,我的回答基本上只是那个答案的概括。奇怪的是,两个如此相似的问题被问得如此接近......
  • 通常你不能从日志文件中推断出太多的执行顺序,除非你的每一行都有时间戳。 IO 是互斥的,因此线程只执行printf 以与锁获取相关的任意顺序。

标签: c linux pthreads


【解决方案1】:

启动顺序连续的,因为创建调用按照它们被写入的顺序发生。

但是无论出于何种原因,调度程序没有按照您希望的顺序调度新启动的线程。如果顺序很重要,也许线程不是您想要的?线程的一大优势是它们并不总是按顺序安排!

如果你真的想要,虽然你可以使用同步原语(例如一系列互斥锁或 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);

这样,在创建线程时,您并不关心实际上哪个线程有机会先运行。

【讨论】:

  • +1 对于“你同步的东西越多,首先有线程的意义就越小。”
【解决方案2】:

我认为你并不真正关心哪个线程先执行。如果您只需要四个线程的唯一标识符,请检查 pthread_self。要获得顺序 ID,请从线程内调用 ID 分配器;或在调用 pthread_create 时生成 ID 并将其作为用户参数传递。

【讨论】:

    【解决方案3】:

    在我使用的解决方案之后

    #include <pthread.h>
    #include <stdio.h>
    
    static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
    static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
    static bool wait = TRUE;
    
    void thread_sync() {
      pthread_mutex_lock(&mut);
      wait = FALSE;
      pthread_cond_signal(&cond);
      pthread_mutex_unlock(&mut);
    }
    void thread_wait_sync() {
      pthread_mutex_lock(&mut);
      if (wait==TRUE)
      {
          pthread_cond_wait(&cond,&mut);
      }
      wait = TRUE;
      pthread_mutex_unlock(&mut);
    }
    
    void *thread1(void *d) {
      thread_sync();
      while (1); // Rest of work happens whenever
      return NULL;
    }
    
    void *thread2(void *d) {
      thread_sync();
      while (1);
      return NULL;
    }
    
    void *thread3(void *d) {
      thread_sync();
      while (1);
      return NULL;
    }
    
    void *thread4(void *d) {
      while (1);
      return NULL;
    }
    
    int main() {
      pthread_t t1,t2,t3,t4;
      pthread_create(&t1, NULL, thread1, NULL);
      thread_wait_sync();
      pthread_create(&t2, NULL, thread2, NULL);
      thread_wait_sync();
      pthread_create(&t3, NULL, thread3, NULL);
      thread_wait_sync();
      pthread_create(&t4, NULL, thread4, NULL);
      while(1) {
        // some work
      }
    }
    

    【讨论】:

      【解决方案4】:
      Move 'pthread_create(thread2,NULL,thread_func2,NULL);' into thread_func1()
      Move 'pthread_create(thread3,NULL,thread_func2,NULL);' into thread_func2()
      Move 'pthread_create(thread4,NULL,thread_func2,NULL);' into thread_func3()
      

      这与最近发布的另一个问题非常接近,并且同样错误..'奇怪'

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2023-02-11
        • 2021-11-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多