【发布时间】:2011-04-14 23:41:46
【问题描述】:
我一直在使用 pthread 库在 C 中创建和加入线程。
我什么时候应该从一开始就创建一个分离的线程?与可连接线程相比,它是否提供任何性能优势?
在可连接(默认)线程上不执行
pthread_join()是否合法?或者这样的线程应该总是在pthread_exit()ing之前使用detach()函数?
【问题讨论】:
我一直在使用 pthread 库在 C 中创建和加入线程。
我什么时候应该从一开始就创建一个分离的线程?与可连接线程相比,它是否提供任何性能优势?
在可连接(默认)线程上不执行pthread_join() 是否合法?或者这样的线程应该总是在pthread_exit()ing之前使用detach()函数?
【问题讨论】:
当你知道你不想用pthread_join() 等待它时,创建一个分离的线程。唯一的性能优势是,当分离的线程终止时,可以立即释放其资源,而不必等待线程加入才能释放资源。
不加入可连接线程是“合法的”;但通常不建议这样做,因为(如前所述)在线程加入之前不会释放资源,因此如果您不加入,它们将无限期地保持绑定(直到程序退出)。
【讨论】:
exit() 或 _exit() 或 _Exit(),我在 POSIX 文档中找不到任何指示其他线程继续运行的内容。如果主线程执行pthread_exit(),那么其他线程确实有机会完成。
我什么时候应该从一开始就创建一个分离的线程?
只要应用程序不关心线程何时完成并且也不关心线程的返回值(线程可以通过pthread_exit 将值传回给其他线程/应用程序)。
例如,在客户端-服务器应用程序模型中,服务器可能会创建一个新线程来处理每个请求。但是服务器本身并不关心线程的线程返回值。在这种情况下,创建 detached 线程是有意义的。
服务器唯一需要确保的是当前处理的请求已经完成。它可以这样做,只需退出主线程而不退出整个程序/应用程序。当进程中的最后一个线程退出时,应用程序/程序自然会退出。
伪代码可能如下所示:
/* A server application */
void process(void *arg)
{
/* Detach self. */
pthread_detach(pthread_self());
/* process a client request. */
pthread_exit(NULL);
}
int main(void)
{
while (not_done) {
pthread_t t_id;
errno = pthread_create(&t_id, NULL, process, NULL);
if (errno) perror("pthread_create:");
}
/* There may be pending requests at this point. */
/* Just exit the main thread - not the whole program - so that remaining
requests that may still be processed can continue. */
pthread_exit(NULL);
}
另一个示例可能是守护程序或记录器线程,只要应用程序运行,它就会定期记录一些信息。
与可连接线程相比,它是否提供任何性能优势?
性能方面,joinable 线程与 detached 线程之间没有区别。唯一的区别是,对于分离的线程,它的资源(例如线程堆栈和任何相关的堆内存等等——构成这些“资源”的确切内容是特定于实现的)。
不在可连接(默认)线程上执行 pthread_join() 是否合法?
是的,不加入线程是合法的。 pthread_join 只是一个方便的功能,除非您需要,否则绝不需要使用。但请注意,创建的线程默认是可加入线程。
您可能想要加入的一个示例是线程执行在它们之间拆分的“一块”工作。在这种情况下,您需要在继续之前检查所有线程是否已完成。 Task farm parallelism 就是一个很好的例子。
或者这样的线程应该总是在 pthread_exit()ing 之前使用 detach() 函数吗?
没有必要。但您通常想在创建时决定是要 joinable 还是 detached 线程。
请注意,虽然可以通过调用pthread_attr_setdetachstate 设置属性PTHREAD_CREATE_DETACHED 来创建可分离线程,但线程决定可以决定在任何时间点分离自身,例如与pthread_detach(pthread_self())。此外,具有另一个线程的线程 ID (pthread_t) 的线程可以与 pthread_detach(thread_id); 分离。
【讨论】:
pthread_exit 只会退出该线程,如果有其他线程在运行,该进程将继续运行。这就是我所说的“退出主线程”的意思。 OTOH,例如,从任何线程调用 exit 都会退出整个进程/应用程序。