pthread_exit pthread_join
int pthread_join(pthread_t thread, void **retval);
int pthread_detach(pthread_t thread);
void pthread_exit(void *retval);
线程正常终止的方法:
1、return从线程函数返回。
2、通过调用函数pthread_exit使线程退出
3. 线程可以被同一进程中的其他线程取消。
主线程、子线程调用exit, pthread_exit,互相产生的影响。
1、在主线程中,在main函数中return了或是调用了exit函数,则主线程退出,且整个进程也会终止,
此时进程中的所有线程也将终止。因此要避免main函数过早结束。
2、在主线程中调用pthread_exit, 则仅仅是主线程结束,进程不会结束,进程内的其他线程也不会结束,
知道所有线程结束,进程才会终止。
3、在任何一个线程中调用exit函数都会导致进程结束。进程一旦结束,那么进程中的所有线程都将结束。
为什么要使用pthread_join?
线程终止最重要的问题是资源释放的问题。
线程终止时需要注意线程同步的问题。一般情况下,进程中各个线程的运行是相互独立的,线程的终止不会相互通知,也不会影响其他线程,
终止的线程所占用的资源不会随着线程的结束而归还系统,而是仍为线程所在的进程持有。在Linux中,默认情况下是在一个线程被创建后,
必须使用此函数对创建的线程进行资源回收,但是可以设置Threads attributes来设置当一个线程结束时,直接回收此线程所占用的系统资源,详细资料查看Threads attributes。
函数pthread_join用来等待一个线程的结束,pthread_join的调用者将被挂起并等待thread线程终止。需要注意的是一个线程仅允许一个线程使用pthread_join
等待它结束,并且被等待的线程应该处于可join状态。即非DETACHED状态。DETACHED是指某个线程执行pthread_detach后所处的状态。处于DETACHED状态
的线程无法由pthread_join同步。
一个可pthread_join的线程所占用的资源仅当有线程对其执行了pthread_join后才会释放,因此为了防止内存泄漏,所有线程终止时,要么已经被设置为DETACHED状态
要么使用pthread_join来回收资源。
notice:
一个线程不能被多个线程等待。否则第一个收到信号的线程成功返回。其余调用pthread_join的线程返回错误码
ESRCH No thread with the ID thread could be found.
示例代码:
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h> void* thread_func(void* arg)
{
printf("thread:%lu is running\n", pthread_self());
int rv = ;
pthread_exit((void*)rv);
} int main()
{
pthread_t thid;
int rv; pthread_create(&thid, NULL, thread_func, NULL); printf("main thread begin join\n");
pthread_join(thid, (void*)&rv);
printf("main thread end join\n");
printf("the thread:%lu exit:%d\n", thid, rv); return ;
}
将线程的属性称为detached,则线程退出时会自己清理资源。
void
*start_run(
void
*arg)
{
//dosomework
}
intmain()
{
pthread_t thread_id;
pthread_attr_ tattr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pthread_create(&thread_id, &attr, start_run, NULL);
pthread_attr_destroy( &attr );
sleep(5);
exit
(0);
}
线程可以通过自身执行结束来结束,也可以通过调用pthread_exit()来结束线程的执行。另外,线程甲可以被线程乙被动结束。这个通过调用pthread_cancel()来达到目的。
当然,线程也不是被动的被别人结束。它可以通过设置自身的属性来决定如何结束,线程的被动结束分为两种,一种是异步终结,另外一种是同步终结。异步终结就是当其他线程调用pthread_cancel的时候,
线程就立刻被结束。而同 步终结则不会立刻终结,它会继续运行,直到到达下一个结束点(cancellation point)。当一个线程被按照默认的创建方式创建,那么它的属性是同步终结。
1 线程取消的定义
一般情况下,线程在其主体函数退出的时候会自动终止,但同时也可以因为接收到另一个线程发来的终止(取消)请求而强制终止。
2 线程取消的语义
1. 线程取消的方法是向目标线程发Cancel信号,但如何处理Cancel信号则由目标线程自己决定,或者忽略(当禁止取消时)、或者立即终止(当在取消点 或异步模式下)、或者继续运行至Cancelation-point(取消点,下面将描述),总之由不同的Cancelation状态决定。
2. 线程接收到CANCEL信号的缺省处理(即pthread_create()创建线程的缺省状态)是继续运行至取消点再处理(退出),或在异步方式下直接 退出。一个线程处理cancel请求的退出操作相当于pthread_exit(PTHREAD_CANCELED)。当然线程可以通过设置为 PTHREAD_CANCEL_DISABLE来拒绝处理cancel请求,稍后会提及。
3. 线程的取消与线程的工作方式(joinable或detached)无关。
3 取消点
根据POSIX标准,pthread_join()、 pthread_testcancel()、pthread_cond_wait()、 pthread_cond_timedwait()、sem_wait()、sigwait()等函数以及read()、write()等会引起阻塞的系 统调用都是Cancelation-point,而其他pthread函数都不会引起Cancelation动作。但是pthread_cancel的手册页声称,由于LinuxThread库与C库结合得不好,因而目前C库函数都不是Cancelation-point;但CANCEL信号会使线程从阻塞的系统调用中退出,并置EINTR错误码,因此可以在需要作为Cancelation-point的系统调用前后调用pthread_testcancel(),从而达到POSIX标准所要求的目标,即如下代码段:
pthread_testcancel();
retcode = read(fd, buffer,length);
pthread_testcancel();
使用前 须判断线程ID的有效性!即判断并保证:thrd != 0 否则有可能会出现“段错误”的异常!
4 程序设计方面的考虑
1. 如果线程处于无限循环中,且循环体内没有执行至取消点的必然路径,则线程无法由外部其他线程的取消请求而终止。因此在这样的循环体的必经路径上应该加入pthread_testcancel()调用。
2. 当pthread_cancel()返回时,线程未必已经取消,可能仅仅将请求发送给目标线程,而目标线程目前没有到达取消点,如果要知道线程在何时中止,就需要在取消它之后调用pthread_join()。有一个例外是当线程被detach后,不能这样处理:
a) 当join一个已经detached的线程时,返回EINVAL;
b) 如果join后该线程设置为detached,则detach将不起作用。
因此,如果知道一个线程可能会以分离方式运行,就不需要在pthread_cancel()后调用pthread_join()。
5 与线程取消相关的pthread函数
int pthread_cancel(pthread_t thread)
发送终止信号给thread线程,如果成功则返回0,否则为非0值。发送成功并不意味着thread会终止。
int pthread_setcancelstate(int state, int *oldstate)
设 置本线程对Cancel信号的反应,state有两种值:PTHREAD_CANCEL_ENABLE(缺省)和 PTHREAD_CANCEL_DISABLE,分别表示收到信号后设为CANCLED状态和忽略CANCEL信号继续运行;old_state如果不为 NULL则存入原来的Cancel状态以便恢复。
int pthread_setcanceltype(int type, int *oldtype)
设 置本线程取消动作的执行时机,type有两种取值:PTHREAD_CANCEL_DEFFERED 和 PTHREAD_CANCEL_ASYCHRONOUS,仅当Cancel状态为Enable时有效,分别表示收到信号后继续运行至下一个取消点再退出和 立即执行取消动作(退出);oldtype如果不为NULL则存入运来的取消动作类型值。
void pthread_testcancel(void)
检查本线程是否处于Canceld状态,如果是,则进行取消动作,否则直接返回。
6 检测一个线程是否还活着的pthread函数
int pthread_kill(pthread_t thread, int sig)
向指定ID的线程发送sig信号,如果线程的代码内不做任何信号处理,则会按照信号默认的行为影响整个进程。也就是说,如果你给一个线程发送了SIGQUIT,但线程却没有实现signal处理函数,则整个进程退出。
pthread_kill(threadid, SIGKILL)也一样,他会杀死整个进程。
如果要获得正确的行为,就需要在线程内实现signal(SIGKILL,sig_handler)。
所以,如果int sig的参数不是0,那一定要清楚到底要干什么,而且一定要实现线程的信号处理函数,否则,就会影响整个进程。
那么,如果int sig的参数是0呢,这是一个保留信号,一个作用就是用来判断线程是不是还活着。
我们来看一下pthread_kill的返回值:
线程仍然活着:0
线程已不存在:ESRCH
信号不合法:EINVAL
#include<stdio.h>
#include<unistd.h>
#include<signal.h>
#include<pthread.h>
#include<time.h> pthread_t tid;
sigset_t set; void myfunc()
{
printf("hello\n:");
} void* mythread(void* p)
{
int signum;
while()
{
sigwait(&set, &signum); if (SIGUSR1 == signum)
{
myfunc();
}
else if (SIGUSR2 == signum)
{
printf("I will sleep 2 seconds and exit\n");
sleep();
break;
}
}
} int main()
{
char tmp;
void *status;
sigemptyset(&set);
sigaddset(&set,SIGUSR1);
sigaddset(&set,SIGUSR2);
sigprocmask(SIG_SETMASK,&set,NULL);
pthread_create(&tid,NULL,mythread,NULL); printf(":");
while()
{
char* p = NULL;
char str[]; scanf("%c",&tmp);
p = gets(str); //printf("get %c\n", tmp);
if('a'==tmp)
{
pthread_kill(tid,SIGUSR1);//发送SIGUSR1,打印字符串。
sleep();
}
else if('q'==tmp)
{
//发出SIGUSR2信号,让线程退出,如果发送SIGKILL,线程将直接退出。
pthread_kill(tid,SIGUSR2);
//等待线程tid执行完毕,这里阻塞。
pthread_join(tid,&status);
printf("finish\n");
break;
}
else
{
printf(":");
} }
return ;
}
pthread_exit pthread_join的更多相关文章
- 多线程:pthread_exit,pthread_join,pthread_self
/*exit_join_id.c*/ #include<pthread.h> #include<stdio.h> void* eji(void* agr) { printf(& ...
- 线程正常终止pthread_exit,pthread_join,pthread_kill,pthread_cancel,sigwait,sigaddset
int pthread_join(pthread_t thread, void **retval); int pthread_detach(pthread_t thread); void pthrea ...
- Linux多线程学习总结
线程是程序中完成一个独立任务的完整执行序列,即一个可调度的实体:进程相当于运行中程序的一种抽象.根据运行环境的调度者的身份,线程可分为内核线程和用户线程.内核线程,在有的系统上称为LWP(Light ...
- LINUX多线程(一)(创建和退出)
1. Linux多线程概述 1.1. 概述 进程是系统中程序执行和资源分配的基本单位.每个进程有自己的数据段.代码段和堆栈段.这就造成进程在进行切换等操作时都需要有比较负责的上下文切换等动作.为了进一 ...
- 操作系统学习笔记----进程/线程模型----Coursera课程笔记
操作系统学习笔记----进程/线程模型----Coursera课程笔记 进程/线程模型 0. 概述 0.1 进程模型 多道程序设计 进程的概念.进程控制块 进程状态及转换.进程队列 进程控制----进 ...
- Pthread:POSIX 多线程程序设计【转】
转自:http://www.cnblogs.com/mywolrd/archive/2009/02/05/1930707.html#phtread_ref POSIX 多线程程序设计 Blaise ...
- [posix]Posix多线程编程
就不排版了,可以到原作者博客下看 转自:http://www.cnblogs.com/zhangsf/archive/2013/09/09/3309867.html 目录表 摘要 译者序 Pthre ...
- Thread and Peocess
Thread and Peocess pthread_create() 原型: int pthread_create(pthread_t* thread, pthread_attr_t* attr, ...
- Linux多线程实例练习 - pthread_exit() 与 pthread_join()
Linux多线程实例练习 - pthread_exit 与 pthread_join pthread_exit():终止当前线程 void pthread_exit(void* retval); pt ...
随机推荐
- 基于Linux的Samba开源共享解决方案测试(三)
在极限写场景下,对于网关的网络监控如图: 在极限写场景下,对于网关的网络监控如图: 在极限混合读写场景下,对于网关的网络监控如图: 在极限混合读写场景下,对于客户端的网络监控如图: 双NAS网关100 ...
- 一起KVM环境下windows7虚拟机异常死机(BSOD)的问题解决
先说一下环境: 一.硬件 8台服务器做的超融合架构,软件存储池, 每台服务器是96G内存,两颗Intel(R) Xeon(R) CPU E5-2670 0 @ 2.60GHz,32线程. 每台服务器是 ...
- mavenProfile文件配置和简单入门
1什么是MavenProfile 在我们平常的java开发中,会经常使用到很多配制文件(xxx.properties,xxx.xml),而当我们在本地开发(dev),测试环境测试(test),线上生产 ...
- 使用REGINI修改注册表权限
regini regset.ini 就行啦 regset.ini 是你要修改的数据 1.注册表修改 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Curr ...
- JS 时间 获取 当天,昨日,本周,上周,本月,上月
调用 setTimeRange (2); function setTimeRange (v) { var fmt = 'YYYY-MM-DD HH:mm'; var now = new Date() ...
- ActiveMQ无法启动
解决办法:activemq无法启动,端口被占用 用netstat -an无法查出61616被哪个进程占用(实践证明,netstat -ano|findstr '61616'什么也没有找到) 经过排查和 ...
- WINFORM小列子参考
1.用树型列表动态显示菜单 密码:zx9t 二.Popup窗口提醒(桌面右下角出现) 密码:cjjo 三.台历 密码:nq4m 四.文件复制 密码:lsqj 五.进度条 密码:byti 六 ...
- Optimizing graphics performance
看U3D文档,心得:对于3D场景,使用分层次的距离裁剪,小物件分到一个层,稍远时就被裁掉,大物体分到一个层,距离很远时才裁掉,甚至不载.中物体介于二者之间. 文档如下: Good performanc ...
- MySql PartionBy
SELECT tableOld.*, if(@channelName = tableOld.channelName, @rank := @rank + 1, @rank := 1) AS rank, ...
- 调整Mic音量
uses MMSystem; function GetLineInHandle(AudioType : integer) : integer;var i : integer; AudioCaps ...