【问题标题】:How to join with whichever thread finishes first?如何加入先完成的线程?
【发布时间】:2017-05-27 00:11:32
【问题描述】:

主线程产生 > 1 个线程,每个线程都可以调用 return 并返回一个错误值。如果发生这种情况,其他线程继续没有意义,应该取消。

所以,我希望我的主线程:

  • 加入先完成的线程;
  • 检查该线程是否返回错误,如果是,则取消所有其他线程。

但是,pthread_join 要求我指定要加入的线程。例如,如果我调用pthread_join(thread1, thread1_ret),并且thread2 以错误结束,那么我将无法知道thread2 在thread1 结束之前完成错误,以及thread2 过早结束的事实很可能意味着thread1 当前正在等待一个永远不会发出信号的条件变量,因为只有thread2 可能会发出该变量的信号……所以,不好。

如果thread2 完成,我希望我的主线程取消thread1,反之亦然。

如何做到这一点?

【问题讨论】:

    标签: multithreading pthreads pthread-join


    【解决方案1】:

    如何做到这一点?

    您需要一个单独的沟通渠道。

    一个典型的解决方案涉及一个队列(已完成的线程)和一个条件变量。

    以错误结束的线程将自己放入队列并在返回之前发出条件信号。主线程等待条件,检查队列,并加入它在那里找到的线程,然后取消所有其他线程。

    还要注意,异步线程取消很难正确处理。通常最好有一个所有线程定期检查的全局变量:while (!exit_requested) { do_work(); }

    【讨论】:

      【解决方案2】:

      你想要这样的东西:

      struct thread_data {
        int stop;
        pthread_cond_t * flag;
        pthread_mutex_t * lock;
        int * failCount;
        int * successCount;
      };
      
      void * foobar(void * ptr)
      {
        struct thread_data * data = (struct thread_data*)ptr;
        int fail = 0;
        while (isWorkToBeDone() && !data->stop) {
          // do some work
      
          if (encounteredError()) {
            pthread_mutex_lock(data->lock);
            data->failCount += 1;
            fail = 1;
            pthread_cond_signal(data->flag);
            pthread_mutex_unlock(data->lock);
          }
        }
      
        // clean up
        if (!fail) {
          pthread_mutex_lock(data->lock);
          data->successCount += 1;
          pthread_cond_signal(data->flag);
          pthread_mutex_unlock(data->lock);
        }
      
        pthread_exit(NULL);
      }
      
      
      int runThreads()
      {
        pthread_t * threads;
      
        pthread_mutex_t lock;
        pthread_cond_t flag;
      
        int i;
        struct thread_data data;
      
        threads = malloc(sizeof(*threads)*numThreads);
        if (!threads) {
          // handle malloc error
          return 0;
        }
      
        // initialize mutex and condition variable
        pthread_mutex_init(&lock, NULL);
        pthread_cond_init(&flag, NULL);
      
        data.stop = 0;
        data.flag = &flag;
        data.lock = &lock;
        data.failCount = 0;
        data.successCount = 0;
      
        for (i = 0; i < numThreads; ++i) {
          if (!pthread_create(threads+i, NULL, foobar,
              (void *)(threads+i))) {
            // handle thread creation error
          }
        }
      
        while (!data.stop) {
          pthread_mutex_lock(&lock);
          pthread_cond_wait(&cond, &lock);
          // a thread just finished
          if (data.failCount > 0) {
            data.stop = 1;
          } else if (data.successCount == numThreads) {
            data.stop = 1;
          }
          pthread_mutex_unlock(&lock);
        }
      
        for (i = 0; i < numThreads; ++i) {
          pthread_join(threads[i], NULL);
        }
      
        pthread_mutex_destroy(&lock);
        pthread_cond_destroy(&flag);
        free(threads);
      }
      

      它的工作方式是等待一个线程失败或所有线程成功,然后通过stop 变量让所有线程知道停止工作并干净退出。

      您可以调用pthread_kill(),而不是让线程检查stop 变量,但是干净地退出每个线程要好得多。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-10-10
        • 1970-01-01
        • 2021-05-14
        • 1970-01-01
        • 2019-12-17
        • 2012-03-25
        • 1970-01-01
        相关资源
        最近更新 更多