我有一个TCP服务器应用程序,它使用POSIX Threads和C ++为新线程中的每个客户端提供服务。
服务器在其套接字上调用“listen”,当客户端连接时,它会生成Client类的新对象。新对象在其自己的线程中运行并处理客户端的请求。
当客户端断开连接时,我想要某种方式告诉我的main()线程该线程已完成,而main()可以删除此对象并记录“Client disconnected”之类的内容。
我的问题是,我如何告诉主线程,线程已完成?
答案 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的使用有所帮助。 简言之:
这方面的潜在问题是我没有将pthread_tryjoin_np视为部分官方POSIX标准,因此该解决方案可能无法移植。