方法
pthread_join(thread, status)
pthread_detach(thread)
pthread_attr_setdetachstate(attr, detachstate)
pthread_attr_getdetachstate(attr)
连接
连接(joining)是一种线程之间完成同步的方法,举例如下。
pthread_join()方法会阻塞调用它的线程,直到相关的线程终止运行。如果相关线程调用了pthread_exit(),编程人员能够在主线程中获取相关线程终止时的具体信息(即pthread_exit()的参数会传递给pthread_join())。
一个线程只能被连接一次,对单个线程进行多次连接错误会导致逻辑错误。
用于线程间同步的另外两种方法:互斥量和条件变量将在后续章节中讲述。
能否连接
线程被创建时,它的一个属性决定其是能够被连接的或者是已经分离的,只有属性为能够被连接的线程才可以通过调用pthread_join() 对其进行连接。如果一个线程的属性为已分离的,那么它不能够被连接。
POSIX标准中要求创建的线程应该为可连接的。我们可以通过设置pthread_create()中的attr参数来设置创建线程时的这个属性,对attr的使用流程如下。
- 声明一个pthread_attr_t类型的变量
- 使用pthread_attr_init()对其初始化
- 使用pthread_attr_setdetachstate()设置变量的可连接/分离属性
- 变量使用结束后,使用pthread_attr_destroy()销毁该变量
分离
pthread_detach()方法用于显式地分离一个线程,即使它被创建时相关属性为可连接;没有对应的逆向操作的方法。
建议
如果一个线程需要被连接,在创建它时就设为可连接的属性。因为一些平台的实现中线程创建时可能属性的默认值不是可连接的,这样做代码的健壮性、可移植性更高。
如果事先确定一个线程永远不可能被连接,可以考虑将其初始化时的属性设为分离的,这样可以减少系统负载。
示例程序
/*****************************************************************************
* FILE: join.c
* DESCRIPTION:
* This example demonstrates how to "wait" for thread completions by using
* the Pthread join routine. Threads are explicitly created in a joinable
* state for portability reasons. Use of the pthread_exit status argument is
* also shown. Compare to detached.c
* AUTHOR: 8/98 Blaise Barney
* LAST REVISED: 01/30/09
******************************************************************************/
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#define NUM_THREADS 4
void *BusyWork(void *t)
{
int i;
long tid;
double result=0.0;
tid = (long)t;
printf("Thread %ld starting...\n",tid);
for (i=0; i<1000000; i++)
{
result = result + sin(i) * tan(i);
}
printf("Thread %ld done. Result = %e\n",tid, result);
pthread_exit((void*) t);
}
int main (int argc, char *argv[])
{
pthread_t thread[NUM_THREADS];
pthread_attr_t attr;
int rc;
long t;
void *status;
/* Initialize and set thread detached attribute */
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
for(t=0; t<NUM_THREADS; t++) {
printf("Main: creating thread %ld\n", t);
rc = pthread_create(&thread[t], &attr, BusyWork, (void *)t);
if (rc) {
printf("ERROR; return code from pthread_create() is %d\n", rc);
exit(-1);
}
}
/* Free attribute and wait for the other threads */
pthread_attr_destroy(&attr);
for(t=0; t<NUM_THREADS; t++) {
rc = pthread_join(thread[t], &status);
if (rc) {
printf("ERROR; return code from pthread_join() is %d\n", rc);
exit(-1);
}
printf("Main: completed join with thread %ld having a status of %ld\n",t,(long)status);
}
printf("Main: program completed. Exiting.\n");
pthread_exit(NULL);
}
运行后输出信息如下
Main: creating thread 0
Main: creating thread 1
Thread 0 starting...
Main: creating thread 2
Thread 1 starting...
Main: creating thread 3
Thread 2 starting...
Thread 3 starting...
Thread 1 done. Result = -3.153838e+06
Thread 0 done. Result = -3.153838e+06
Main: completed join with thread 0 having a status of 0
Main: completed join with thread 1 having a status of 1
Thread 3 done. Result = -3.153838e+06
Thread 2 done. Result = -3.153838e+06
Main: completed join with thread 2 having a status of 2
Main: completed join with thread 3 having a status of 3
Main: program completed. Exiting.