|
线程终止时,一个需要注意的问题是线程间的同步问题。一般情况下,进程中各个线程的运行是相互独立的,线程的终止并不会相互通知,也不会影响其他线程,终止的线程所占用的资源不会随着线程的终止而归还系统,而是仍然为线程所在的进程持有。正如进程间可以用 wait()系统调用来等待其他进程结束一样,线程也有类似的函数:pthread_join(),在 pthread.h 头文件中声明如下:
#include <pthread.h>
int pthread_join(pthread_t th, void *thread_return);
int pthread_tetach(pthread_t th); 函数 pthread_join() 用来等待一个线程的结束。pthread_join() 的调用者将被挂起并等待 th 线程终止,如果 thread_return 不为 NULL,则 *thread_return=retval。需要注意的是,一个线程仅允许一个线程使用 pthread_join() 等待它的终止,并且被等待的线程应该处于可 join 状态,即非 DETACHED 状态。DETACHED 状态是指对某个线程执行 pthread_detach() 后其所处的状态。处于 DETACHED 状态的线程无法由 pthread_join() 同步。
一个可 "join" 的线程所占用的内存仅当有线程对其执行了 phread_join() 后才会释放,因此为了避免内存泄露,所有线程终止时,要么设为 DETACHED ,要么使用 pthread_join() 来回收资源。
注意:一个线程不能被多个线程等待,否则第一个接收信号的线程成功返回,其余调用 pthread_join() 的线程返回错误代码 ESRCH 。
测试程序:
#include <stdio.h>
#include <pthread.h>
void assisthread(void *arg)
{
printf("I am helping to do some jobs\n");
sleep(3);
pthread_exit(0);
}
int main(void)
{
pthread_t assistthid;
int status;
pthread_create(&assistthid, NULL, (void *)assisthread, NULL);
pthread_join(assistthid, (void *)&status);
printf("assistthid's exit is caused %d\n", status);
return 0;
} 运行及输出:beyes@linux-beyes:~/C/base> ./jointhread.exe
I am helping to do some jobs
assistthid's exit is caused 0 说明:
从运行结果可以看出 pthread_join() 会阻塞主线程,等待线程 assisthread 结束。pthread_exit() 结束时的退出码是0,pthread_join 得出的 status 也为 0,两者是一致的。
例-2:
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void *thread_malloc (char *parameter)
{
int *p;
p = (int *)malloc (10 * sizeof(int)); /*申请空间*/
printf ("传进来的参数是 %s\n", parameter);
printf ("该线程ID是 %u\n", pthread_self());
memset (p, 'c', 10);
printf ("刚才申请的空间首地址为: 0x%x\n", p);
pthread_exit (p); //退出线程,返回申请空间首址
}
int main (int argc, char **argv)
{
int error;
int *temptr;
pthread_t thread_id;
/*创建线程*/
pthread_create (&thread_id, NULL, (void *)*thread_malloc, "thread malloc");
/*线程结束时返回值存放在pthread_join()函数的第 2 个参数里*/
if (error = pthread_join (thread_id, (void **)&temptr)) {
perror ("thread_join");
exit (EXIT_FAILURE);
}
printf ("线程返回的指针地址是: 0x%x\n", temptr);
printf ("线程申请的空间没被回收,现在打印出此空间第一个字节的值:%c\n", *temptr);
*temptr = 'd'; //改变堆空间值,测试是否可用
printf ("更改后的值为: %c\n", *temptr);
free (temptr); //释放该堆空间
return (0);
} 运行与输出:./thread_exit_test
传进来的参数是 thread malloc
该线程ID是 3075955568
刚才申请的空间首地址为: 0x804b098
线程返回的指针地址是: 0x804b098
线程申请的空间没被回收,现在打印出此空间第一个字节的值:c
更改后的值为: d 说明:
上面的代码验证了线程退出时全局变量、局部变量和堆空间是如何管理的。在上面程序中,首先在主线程中创建一个新线程,在新线程中申请一段堆空间并赋值,然后作为该线程的返回值。在主线程中,等待该子线程结束,并存储其退出状态。此程序如果没有出现异常,那么子线程中申请的堆空间在主线程中也可以访问并释放,这说明了子线程退出时仅释放其私有的栈空间(局部数据)。显然,位于数据段的全局数据是不会在线程退出时释放的,只有当进程退出时才释放。 |
|