我是多线程的新手,我需要全面了解“连接”,我是否需要加入我的应用程序中的每个线程?以及它如何与多线程一起工作?
答案 0 :(得分:8)
不,如果你想让它独自一个,你可以分离一个线程。 如果你启动一个线程,要么你要分离它,要么在程序结束之前加入它,否则这是未定义的行为。
要知道线程需要分离,你需要问自己这个问题:“我希望线程在程序主函数完成后运行吗?”。以下是一些例子:
当您执行文件/新建时,您创建一个新线程并将其分离:当用户关闭文档时线程将被关闭在这里不需要来加入线程
当您执行蒙特卡罗模拟,某些分布式计算或任何Divide And Conquer类型算法时,您启动所有线程,您需要等待所有结果,以便您可以将它们组合在一起。在结合结果之前,您明确需要加入线程
答案 1 :(得分:2)
pthread_join()函数暂停执行调用线程 直到目标线程终止,除非目标线程有 已经终止了。从成功的pthread_join()调用返回时 使用非NULL value_ptr参数,传递给pthread_exit()的值 通过终止线程在引用的位置提供 通过value_ptr。当pthread_join()成功返回时,目标 线程已被终止。多个同时通话的结果 到pthread_join()指定相同的目标线程是未定义的。如果 调用pthread_join()的线程被取消,然后是目标线程 不会脱离。
所以pthread_join做了两件事:
等待线程完成。
清理所有相关资源 与线程。
这意味着如果您在不调用pthread_join的情况下退出流程,则操作系统将为您完成(2)(尽管它不会执行线程取消清理) ,(1)将不会完成。
因此,您是否需要致电pthread_join取决于您是否需要(1)发生。
如果您不需要运行该线程,那么您也可以pthread_detach。分离的线程无法连接(因此您无法等待其完成),但如果资源完成,则会自动释放其资源。
答案 2 :(得分:1)
我是否需要加入我的应用程序中的每个线程?
不一定 - 取决于您的设计和操作系统。 Join()在GUI应用程序中是主动危险的 - 倾向如果您不需要知道或不关心知道一个线程是否已从另一个线程终止,您不需要加入它。
我非常努力地不加入/ WaitFor任何线程。池线程,应用程序生命周期线程等通常不需要任何显式终止 - 取决于操作系统以及线程是否拥有或明确绑定到需要显式终止/关闭/无论什么的任何资源。
答案 3 :(得分:1)
线程可以是可连接的也可以是分离的。不应连接分离的线程。另一方面,如果你没有加入可连接线程,你的应用程序会泄漏一些内存和一些线程结构。 c ++ 11 std :: thread会调用std :: terminate,如果它没有被标记为已分离且线程对象超出范围而没有调用.join()
。请参阅pthread_detach和pthread_create。这与流程非常相似。当孩子退出时,它将保持为zombee,而它的创造者不会打电话给waitpid
。这种行为的共鸣是线程和进程的创建者可能想知道退出代码。
更新:如果在属性参数等于NULL(使用默认属性)的情况下调用pthread_create
,则将创建可连接线程。要创建分离的线程,可以使用属性:
pthread_attr_t attrs;
pthread_attr_init(&attrs);
pthread_attr_setdetachstate(&attrs, PTHREAD_CREATE_DETACHED);
pthread_create(thread, attrs, callback, arg);
此外,您可以通过在创建的pthread_detach
上调用pthread_join
来分离线程。如果您尝试使用分离的线程加入,EINVAL
将返回pthread_getattr_np
错误代码。 glibc有一个非可移植扩展pthread_attr_getdetachstate
,它允许获取正在运行的线程的属性。因此,您可以使用{{1}}检查线程是否已分离。
答案 4 :(得分:1)
不加入某个帖子就像delete
不是new
所有内存一样。它可能是无害的,也可能是一种坏习惯。
您未与之同步的线程处于未知执行状态。如果它是一个文件编写线程,它可能是编写文件的一半,然后应用程序完成。如果它是一个网络通信线程,它可能是握手的一半。
加入每个主题的缺点是,如果其中一个进入了糟糕状态并且已被阻止,那么您的应用可能会挂起。
通常,您应该尝试向未完成的主题发送消息,告诉他们退出并清理。然后你应该等待一段适当的时间让他们完成或以其他方式回应他们好死,然后关闭应用程序。在此之前,您应该表示您的程序不再开放营业 - 关闭GUI窗口,响应您正在关闭的其他进程的请求等 - 所以如果这需要比预期更长的时间,则用户不会受到打扰。最后,如果事情不完美 - 如果线程拒绝响应您的请求,他们关闭并且您放弃它们 - 那么您也应该记录错误,这样您就可以解决可能是更大问题的症状。 / p>
上一次工作线程意外挂起我最初认为是网络中断和超时代码中的错误。经过深入检查,这是因为在关闭同步之前使用的其中一个对象是delete
d:在我的再现案例中看起来像挂起的未定义行为。如果我们没有仔细加入,那么这个bug就更难以追踪(现在,正确的做法是使用我们无法删除的共享资源:但是会发生错误)。