【问题标题】:Pthread_join() : resources collector : whaiting multiple threads to exitPthread_join() :资源收集器:等待多个线程退出
【发布时间】:2011-04-13 14:16:41
【问题描述】:

我正在编写一个并发(多线程)服务器应用程序 - 当然是使用 pthread!- 当我遇到 pthread_join 问题时,我的应用是 shuch(伪代码):

/* Sheduler thread */
while (1) {

   c = get_client();
   r = get_resource();

   communication.c = c;
   communication.r = r;

   pthread_create( clnt_tid, null, clnt_fn, communication);
   resource_alloc_list_add(clnt_tid, r);

}

/* resources Collector thread */
while(!rs_alloc_list_is_empty()) {

   e = get_elt(rs_alloc);
   pthread_join(e.clnt_tid, retour);
   free_rs(e.r);
}
.........

问题是没有非阻塞的 pthread_join 调用——有一个但它不是可移植的——并且 pthread_join 不能像进程编程中的 wait() 那样加入任何线程。因此,如果 rsc_collector 线程正在等待一个客户端线程退出以取回分配的资源,并且在此之前所有其他线程都已退出,那么它们的资源将被阻塞 - 并且调度程序线程无法为其他客户端提供服务 - 直到第一个线程终止了他的工作。 你能告诉我这个问题的可能解决方案吗?

编辑:

我会更具体地说,我正在编写本地资源管理系统 (lrms) 或远程程序执行系统,有三个不同的程序:客户端 pg、服务器 pg 和调度程序 pg,客户端联系调度程序和等待调度程序 pg 为他分配一个空闲服务器,以便他可以在提交后在远程服务器上执行他的作业。调度 pg 将在客户端队列中排队客户端地址。在另一边,服务器 pg 向调度程序发送注册消息并等待作业,调度程序将服务器地址排入资源队列中(所以我的意思是远程服务器的资源不是系统分配给线程的资源)。 调度程序 pg 由三个主线程组成:

  • main_thread : 在知名端口绑定的套接字上列出。接收和排队请求和注册(即生产者)
  • scheduler_thread:消费者,de-queue cliets address get server(dequeue a server address),创建客户端线程,保存客户端/服务器分配。然后循环播放。
  • resource_collector 线程:等待客户端线程终止以取回分配的资源。我强调 [*] 为资源收集创建一个特定的线程,因为它对于系统的正确功能非常重要。

注意:

  • 客户端线程获取资源(服务器)的副本而非原始资源。
  • [*] 如果我消除该线程,并让每个客户端释放其资源(远程服务器地址),因此在某些情况下,当客户端线程在调用 free 函数之前崩溃时,资源将永远丢失。 .. 这就是为什么我不会冒险让资源完全控制在客户端线程之下。

【问题讨论】:

  • 如何让客户端线程崩溃...而不使您的程序崩溃...除非您遇到崩溃...在这种情况下您可以释放资源? pthread_cleanup_push/pop 是否适用?
  • 首先我为延迟道歉。其次,是的,pthread_cleanup_push/pop 适用,但我正在寻找另一种不使用 pthread_cleanup_push/pop 的解决方案,也许使用标志数组是最好的解决方案。 非常感谢@johnnycrash

标签: pthreads


【解决方案1】:

正如 alexey 之前所说,线程函数可以分配和释放它的资源。如果你想要一个可以处理取消的方法,你也可以使用 pthread_cleanup_push 和 pop。

您可以使用一个全局标志来告诉您线程是否仍然处于活动状态。在创建线程之前将其设置为 1,并在线程函数退出时将其设置为 0。如果您有很多线程,请使用数组。只需测试变量以查看线程是否已完成。

希望您的收集器线程不会持续旋转,这会消耗资源。

创建线程很慢。您可能希望永久保留少量线程并让它们从队列中挑选工作。当没有工作时,他们应该等待信号。当工作被添加到队列中时,您可以发出信号,只要您想唤醒并重新开始工作即可。这比为每个工作创建一个线程并在工作完成时销毁线程快 1000 倍。

【讨论】:

  • 那么为什么不能像我上面描述的那样分离线程并定期检查全局?你根本不使用 pthread_join。
【解决方案2】:

我建议在退出线程中进行必要的清理,而不是在特殊的收集器线程中。具体来说,使用pthread_key_create() 创建的线程本地数据可能会在线程退出时调用相关的析构函数调用。这个析构函数可以释放与线程关联的应用程序资源;最简单的方法是将指向资源的指针存储在线程特定的槽中(请参阅pthread_set_specific()),在这种情况下,指针将自动发送到析构函数。如果线程一直被创建和销毁,收集器线程仍然可以调用pthread_join();虽然您也可以在分离状态下创建线程,或在创建后调用pthread_detach()

也可以看看之前问过的a similar question

【讨论】:

  • 使用静态客户端线程池需要一些统计研究...我将创建多少线程?系统支持那个数量的线程? -client- 线程的数量必须多于可用的服务器(资源)? ....
猜你喜欢
  • 1970-01-01
  • 2021-03-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-31
  • 1970-01-01
相关资源
最近更新 更多