如何告诉父母线程是使用pthreads在C ++中完成的?

时间:2010-03-22 17:19:55

标签: c++ tcp pthreads

我有一个TCP服务器应用程序,它使用POSIX Threads和C ++为新线程中的每个客户端提供服务。

服务器在其套接字上调用“listen”,当客户端连接时,它会生成Client类的新对象。新对象在其自己的线程中运行并处理客户端的请求。

当客户端断开连接时,我想要某种方式告诉我的main()线程该线程已完成,而main()可以删除此对象并记录“Client disconnected”之类的内容。

我的问题是,我如何告诉主线程,线程已完成?

8 个答案:

答案 0 :(得分:2)

我能看到的最简单的方法是加入线程。见here。我们的想法是,在连接调用中,命令线程将等待工作线程退出,然后继续。

或者,您可以使用一些共享变量和互斥量来推送。

答案 1 :(得分:2)

如果一切正常,pthreads会返回0,或者如果某些内容无效,则会返回errno

int ret, joined;
ret = pthread_create(&thread, NULL, connect, (void*) args);
joined = pthread_join(&thread, NULL);

如果joined为零,则完成线程。清理该线程的对象。

答案 2 :(得分:2)

如果子线程在完成时真正退出(而不是等待更多工作),则父线程可以在其上调用pthread_join,它将阻塞,直到子线程退出。

显然,如果父线程在做其他事情,它就不能在pthread_join上不断阻塞,所以你需要一种方法向主线程发送消息,告诉它调用{{1} }。您可以使用许多IPC机制,但在您的特定情况下(TCP服务器),我怀疑主线程可能是pthread_join循环,对吧?如果是这种情况,我建议使用select来创建逻辑管道,并让管道的读取描述符成为主线程选择的描述符之一。

当子线程完成后,它会向管道写一些消息,说“我已经完成了!”然后服务器会知道在该线程上调用pipe,然后在连接完成时执行其他任何操作。

请注意,除非您需要返回值,否则 不会在已完成的子线程上调用pthread_join。但是,如果子线程具有对共享资源的任何访问权限,通常是一个好主意,因为当pthread_join没有错误地返回时,它会确保子线程确实消失了而不是处于某个中间状态之间已发出“我已完成!”消息,实际上已经退出。

答案 3 :(得分:1)

虽然可以实现IPC机制在其他线程即将终止时通知主线程,但如果你想在线程终止时做某事,你应该尝试让终止线程自己做。

您可以考虑使用pthread_cleanup_push()来建立在线程被取消或退出时要调用的例程。另一种选择可能是使用pthread_key_create()来创建特定于线程的数据键和关联的析构函数。

如果由于阻塞而不想从主线程调用pthread_join(),则应在创建线程或调用pthread_detach()时将其设置为选项来分离客户端线程。

答案 4 :(得分:0)

您可以使用“要删除的线程对象”队列,使用互斥锁保护对队列的访问,然后发出pthread条件变量信号以指示队列中有可用的内容。

但你真的想这样做吗?一个更好的模型是每个线程都可以自行清理,而不用担心首先与主线程同步。

答案 5 :(得分:0)

调用pthread_join将阻止主线程的执行。鉴于问题的描述,我认为它不会提供所需的解决方案。

在大多数情况下,我首选的解决方案是让线程执行自己的清理。如果那是不可能的,你要么必须使用某种带共享变量的轮询方案(只记得使它们线程安全,提示:volatile),或者某种类型的OS依赖回调机制。请记住,您希望在调用listen时被阻止,因此请务必考虑让线程自行清理。

答案 6 :(得分:0)

正如其他人所提到的,使用pthread_join处理给定线程的终止很容易。但是,pthreads的弱点是将来自多个源的信息汇集到同步流中。 (或者,你可以说它的优势在于表现。)

到目前为止,最简单的解决方案是处理工作线程中的清理。记录断开连接(将互斥锁添加到日志中),根据需要删除资源,然后退出工作线程,而不发出父节点信号。

添加互斥锁以允许操作共享资源是一个棘手的问题,因此要灵活且富有创意。在同步时要小心谨慎,并在优化之前进行配置。

答案 7 :(得分:0)

我遇到了和你描述的完全相同的问题。在~300打开客户端连接后,我的Linux应用程序无法创建新线程,因为从未调用pthread_join。对我来说,pthread_tryjoin_np的使用有所帮助。 简言之:

  • 有一个包含所有已打开的线程描述符的地图
  • 在新客户端线程打开之前从主线程
  • 迭代map并为map中记录的每个线程调用pthread_tryjoin_np。如果线程完成,则调用结果为零,这意味着我可以从该线程清理资源。同时pthread_tryjoin_np负责释放线程资源。如果pthread_tryjoin_np调用返回的数字不等于0,则表示该线程仍在运行,我什么都不做。

这方面的潜在问题是我没有将pthread_tryjoin_np视为部分官方POSIX标准,因此该解决方案可能无法移植。