分离式与可连接的 POSIX 线程

66

我一直在使用C语言中的pthread库创建和加入线程。

  1. 什么情况下应该一开始就将线程设置为分离状态?相对于可连接线程,它是否提供任何性能优势?

  2. 在默认情况下可连接线程上不执行pthread_join()是合法的吗?或者这样的线程是否应该在pthread_exit()前总是使用detach()函数?

2个回答

86
  1. 使用 pthread_join()时,如果您知道不想等待线程,则创建一个分离线程。其唯一的性能优势是,当一个分离线程终止时,它的资源可以立即释放,而无需等待线程被加入(joined)才能释放资源。

  2. 不加入可加入的线程是“合法的”,但通常不建议这样做,因为(如前所述)资源不会在线程被加入之前被释放。如果您不加入线程,它们将无限期地保留(直到程序退出)。


疑问:在分离的线程中,如果主线程在分离线程完成之前执行完毕会怎样?我认为这将终止进程并杀死所有线程。那么,在什么情况下使用分离线程呢?因为我必须确保分离线程已经完成执行。 - Ajax
@Ajax:根据经验,如果主线程完成,则程序退出并终止线程。至少在Mac OS X(10.10.1 Yosemite)上似乎是这种行为。我在POSIX文档中找不到任何指示其他线程会继续运行的内容,即使调用了exit()_exit()_Exit()。如果主线程执行pthread_exit(),则其他线程确实有机会完成。 - Jonathan Leffler
另外一点:可分离线程适用于当您已经有其他轮询机制时;您可以使用相同的轮询机制来检查结果状态,以便知道线程是否完成。这是一个“它准备好了吗?如果是,就使用它”的情况。 - Engineer
我可以在线程退出之前调用pthread_detach以避免内存泄漏,如果我忘记调用pthread_join吗? - Antonio Petricca
2
@DareDevil:是的,但是……你应该分离线程,因为你不需要知道线程的返回状态,也不需要知道它是否已经完成,而不是因为你可能会忘记加入它。一旦你分离了线程,就不能尝试加入线程。 - Jonathan Leffler
显示剩余2条评论

5
什么时候应该一开始就创建一个分离线程?
只要应用程序不关心该线程何时完成并且不关心线程的返回值(线程可以通过pthread_exit向其他线程/应用程序传递值)。
例如,在客户端-服务器应用程序模型中,服务器可能会创建一个新线程以处理每个请求。但是,服务器本身不关心线程的线程返回值。在这种情况下,创建分离线程是有意义的。
服务器唯一需要确保的是当前正在处理的请求已完成。它可以通过退出主线程而不退出整个程序/应用程序来实现这一点。当进程中的最后一个线程退出时,应用程序/程序将自然退出。
伪代码如下:
/* 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);
}

另一个示例可能是守护程序或记录器线程,它会在应用程序运行期间定期记录一些信息。

相对于可加入的线程,它是否提供任何性能优势?

就性能而言,在可加入的线程和分离的线程之间没有区别。唯一的区别是使用分离的线程时,其资源(如线程堆栈和任何关联的堆内存等等——这些“资源”是特定于实现的)。

在默认情况下可以不对可加入的线程进行 pthread_join() 操作吗?

是的,可以不加入线程而合法。pthread_join 是一个方便函数,除非需要,否则无需使用。但请注意,创建的线程默认为可加入的线程。

需要加入的一个示例是当线程执行被分割成“片段”的工作时。在这种情况下,您需要在继续之前检查所有线程完成。 任务农场并行 就是一个很好的例子。

或者在pthread_exit()之前,这样的线程是否总是应该使用detach()函数?

不必要。但通常您希望在创建时决定您想要一个可加入(joinable)还是分离(detached)的线程。


请注意,虽然可以通过使用调用pthread_attr_setdetachstate并设置属性PTHREAD_CREATE_DETACHED来创建可分离的线程,但线程可以在任何时候决定自行分离,例如使用pthread_detach(pthread_self())。另外,具有另一个线程的线程 ID(pthread_t)的线程可以使用pthread_detach(thread_id);进行分离。

“退出主线程”和“退出整个程序/应用程序”的区别是什么? - Yd Ahhrk
1
@YdAhhrk 从主线程调用pthread_exit只会退出该线程,如果还有其他线程在运行,则进程将继续运行。这就是我所说的“退出主线程”的意思。另一方面,从任何线程调用exit将退出整个进程/应用程序,例如。 - P.P

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接