连接线程
连接线程是指等待其终止,这可以视为条件变量的特定用法。
等待线程
使用 pthread_join 子例程会使一个线程等待另一个线程终止。 更加复杂的条件(例如,等待多个线程终止)能够通过使用条件变量实现。
调用 pthread_join 子例程
pthread_join 子例程阻塞正在调用的线程,直到指定的线程终止。 目标线程(等待终止的线程)不能拆离。 如果目标线程已经终止,但未拆离,那么 pthread_join 子例程立即返回。 在目标线程被连接之后,会自动将其拆离,并可回收其存储空间。
下表指出当线程调用 pthread_join 子例程时的可能情况,这取决于目标线程的 state 和 detachstate 属性。
| 目标状态 | 未拆离目标 | 已拆离目标 |
|---|---|---|
| 目标仍在运行 | 调用程序被阻塞,直到目标被终止。 | 调用立即返回,并指示有错误。 |
| 目标已终止 | 调用立即返回,并指示成功完成。 |
多个连接
如果目标未被拆离,多个线程可连接同一个目标线程。 此操作是否成功取决于调用 pthread_join 子例程的顺序和目标线程终止的时刻。
- 在目标线程的终止阻塞正在调用的线程之前,可能发生任何对 pthread_join 子例程的调用。
- 目标线程终止时,所有被阻塞的线程均被唤醒,目标线程自动被拆离。
- 发生在目标线程终止之后的任何对 pthread_join 子例程的调用将失败,因为线程被前面的连接拆离。
- 如果在目标线程终止之前没有线程调用 pthread_join 子例程,那么第一次对 pthread_join 子例程的调用将立即返回,并指示成功完成,任何进一步的调用将失败。
连接示例
#include <pthread.h> /* include file for pthreads - the 1st */
#include <stdio.h> /* include file for printf() */
void *Thread(void *string)
{
int i;
/* writes five messages and exits */
for (i=0; i<5; i++)
printf("%s\n", (char *)string);
pthread_exit(NULL);
}
int main()
{
char *e_str = "Hello!";
char *f_str = "Bonjour !";
pthread_attr_t attr;
pthread_t e_th;
pthread_t f_th;
int rc;
/* creates the right attribute */
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr,
PTHREAD_CREATE_UNDETACHED);
/* creates both threads */
rc = pthread_create(&e_th, &attr, Thread, (void *)e_str);
if (rc)
exit(-1);
rc = pthread_create(&f_th, &attr, Thread, (void *)f_str);
if (rc)
exit(-1);
pthread_attr_destroy(&attr);
/* joins the threads */
pthread_join(e_th, NULL);
pthread_join(f_th, NULL);
pthread_exit(NULL);
}线程不能连接自身,因为将发生死锁,且其会被库拆离。 但是,两个线程可能试着互相连接。 它们将死锁,但是这种情况不会被库拆离。
从线程返回信息
pthread_join 子例程还允许线程将信息返回给另一个线程。 当线程调用 pthread_exit 子例程或从其入口点例程返回时,它将返回一个指针 (请参阅 退出线程)。 将存储此指针,直到线程不被拆离,且该指针可被 pthread_join 子例程返回。
/* "scanning" thread */
...
buffer = malloc(...);
/* finds the search pattern in the file
and stores the lines in the buffer */
return (buffer);
/* initial thread */
...
for (/* each created thread */) {
void *buf;
pthread_join(thread, &buf);
if (buf != NULL) {
/* print all the lines in the buffer,
preceded by the filename of the thread */
free(buf);
}
}
...如果目标线程被取消,pthread_join子程序会返回一个-1值,并将其转换为一个指针(请参阅取消线程)。 因为 -1 不可为指针值,将 -1 作为从线程返回的指针意味着线程被取消。
返回的指针可以指向任何类型的数据。 指针必须在线程被终止后仍然有效,且回收其存储空间。 因而,请避免返回值,因为在线程的存储空间被回收时会调用析构函数例程。
void *returned_data;
...
pthread_join(target_thread, &returned_data);
/* retrieves information from returned_data */
free(returned_data);free(returned_data);/* lock - entering a critical region, no other thread should
run this portion of code concurrently */
if (!flag) {
free(returned_data);
flag = 1;
}
/* unlock - exiting the critical region */锁定对关键区域的访问可确保 returned_data 指针仅被释放一次。
返回指向动态分配给多个均执行不同代码的线程的存储空间的指针时,您必须确保恰好仅有一个线程释放指针。