pthread_join() 用于未知数量的线程

Posted

技术标签:

【中文标题】pthread_join() 用于未知数量的线程【英文标题】:pthread_join() for unknown number of threads 【发布时间】:2021-12-05 02:05:00 【问题描述】:

main() 中的 poll() 等待来自另一个应用程序的某种触发器,当有触发器时,执行 pollHandler()。在 pollHandler() 中,我想根据轮询消息中的请求数启动“n”个线程。

但是现在在 pollHandler() 中,当我想在不同的 for 循环中使用 pthread_join 时,我无法访问 thread_ids。我可以创建一个 pthread id 数组并在 pthread_create 和 pthread_join 都可以访问的 for 循环块之外使用它,但是 poll() 函数是活动的,它可以一次又一次地被调用,从而覆盖线程身份证。我如何在这里保持清洁 - 等待每个线程完成并腾出空间来拥有更多线程?


int pollHandler()
int num_req = poll.size();
  for(int i=0; i < num_req; i++)
    // start thread for each req
    pthread_t tid;

    // thread paramters dynamically allocated and freed later
    struct parameters *p = (struct parameters*)malloc(sizeof(struct parameters));

    if((pthread_create(&tid, NULL, thread_func, p) != 0)
      return -1;
    
  

  for(int i=0; i < num_req; i++)
    // pthread_join here but no access to thread ids?
  
 return 0; 


int main()
  ......
  while(1)
    poll(); //waits for a trigger from another application
  



【问题讨论】:

所以你问如何扩展一个数组? realloc 但是你需要清理线程或者有资源耗尽的风险。所以你可能需要一些更复杂的东西。您可能需要某种由线程 ID 键入的关联数组,以便您可以从“中间”删除条目。而且您需要能够在轮询时检测到线程结束。 (或者至少在创建更多线程之前检查哪些线程不再运行)。 未知的线程数?!?!谁在你的进程中跑来跑去并在你不知情的情况下创建线程? 用线程池重新设计 - 创建一个生产者/消费者队列并挂起 128 'while(true)read_queue;程序启动后,process message 立即将其线程化。不要再创建任何线程,也不要尝试终止任何线程。没有加入,没有线程ID,没有线程微管理,没问题。 pthread_join() 很可怕,一出生就扼杀了许多尝试的多线程应用程序:( @ikegami 谢谢 【参考方案1】:

我想根据轮询消息中的请求数启动“n”个线程。

这种设计存在根本缺陷:如果您收到(例如)10,000 个请求的请求,您不太可能创建一个单独的线程来处理每个请求,即使可以,线程的创建和销毁也是效率低下,最好避免。

更好的设计是启动一个线程池,并将工作分派给它们,等待所有工作完成后再返回,正如 Martin James 建议的那样。

也就是说,这是实现您当前设计的正确方法(为清楚起见省略了错误检查):

int pollHandler()
  int num_req = poll.size();
  pthread_t *tids = calloc(num_req * sizeof(pthread_t));
  for(int i=0; i < num_req; i++)
    // start thread for each req
    // thread paramters dynamically allocated and freed later
    struct parameters *p = (struct parameters*)malloc(sizeof(struct parameters));

    if((pthread_create(&tid[i], NULL, thread_func, p) != 0)
// bug here.
      return -1;
    
  

  for(int i=0; i < num_req; i++)
    pthread_join(tids[i], NULL);
  
  free(tids);
  return 0;

我可以创建一个 pthread id 数组并在 pthread_create 和 pthread_join 都可以访问的 for 循环块之外使用它,但是 poll() 函数是活动的,它可以被一次又一次地调用,从而覆盖线程 id。

除非pollHandler() 可以中断另一个pollHandler(),否则它不会在之前的调用完成之前被调用,所以上面的代码是“安全的”。

如果pollHandler() 可以作为中断的一部分运行,那么您的代码已经无可救药地被破坏了(mallocpthread_create 都不是异步信号安全的,因此不能在信号处理程序中调用)。

附: //bug here 怎么了?

您不能只返回那里 - 您需要加入您已经创建的线程。您还需要在那里free(tids);

【讨论】:

谢谢。你是对的,线程数应该有一个上限。另外,pollHandler() 可以被另一个 pollHandler() 打断,所以也许我需要先看看改变这部分设计? 此处有错误,因为我无法访问 pthread_join 的另一个 for 循环中的 thread_id。 @bvj0412 "pollHandler() 可以被打断" -- 你确定吗?被什么打断了?

以上是关于pthread_join() 用于未知数量的线程的主要内容,如果未能解决你的问题,请参考以下文章

pthread_join - 多个线程等待

是否可以在没有 pthread_join() 的情况下使用 pthread?

pthread_join的介绍

SylixOS pthread_join退出

waitformultipleobjects 具有未知数量的句柄

pthread_detach()与pthread_join的区别?