线程非正常终止
- 如果主线程退出,全部线程将强行终止
- 在子线程调用exit(),将终止整个进程
- 终止程序的信号,将导致整体进程终止.(如果某个线程coredump,但影响整个进程) 在多进程程序中,子进程core dump不影响其他进程 在多线程程序中,子线程core dump,整个进程受影响。
终止线程的三种方法
1.线程可以简单的从线程函数中返回,返回值是线程的退出码
2.线程可以被同一进程中的其它线程调用pthread_cancel()取消,主线程中也可以取消子线程
3.在线程函数中,调用pthread_exit(0)退出
return 与pthread_exit的区别就是,如果在子线程的子函数数中return返回到子线程中
如果在子函数中pthread_exit的话,则子线程退出。
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <iostream>
using namespace std;
/*
//int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
// void *(*start_routine) (void *), void *arg);
//int pthread_join(pthread_t thread, void **retval);
线程非正常终止
1. 如果主线程退出,全部线程将强行终止
2. 在子线程调用exit(),将终止整个进程
3. 终止程序的信号,将导致整体进程终止.(如果某个线程coredump,但影响整个进程)
在多进程程序中,子进程core dump不影响其他进程
在多线程程序中,子线程core dump,整个进程受影响。
终止线程的三种方法
1.线程可以简单的从线程函数中返回,返回值是线程的退出码
2.线程可以被同一进程中的其它线程调用pthread_cancel()取消,主线程中也可以取消子线程
3.在线程函数中,调用pthread_exit(0)退出
return 与pthread_exit的区别就是,如果在子线程的子函数数中return返回到子线程中
如果在子函数中pthread_exit的话,则子线程退出。
*/
void *thmain1(void *arg);
void *thmain2(void *arg);
int var=0; //全局变量,所有线程共享进程空间
pthread_t pthid2 = 0;
int main()
{
pthread_t pthid1 = 0;
if(pthread_create(&pthid1, NULL, thmain1, NULL) !=0)
{
cout <<"create pthid1 faile" << endl;
exit(-1);
}
if(pthread_create(&pthid2, NULL, thmain2, NULL) !=0)
{
cout <<"create pthid2 faile" << endl;
exit(-1);
}
//return 0; //1. 如果主线程退出,全部线程将强行终止
// 这里返回的话,没等子线程执行,主线程就退出,什么都没展示
// 这是跟进程不一样的地方,主进程退出,子进程还可以继续执行
//等待子线程退出
cout << "start join..." << endl;
pthread_join(pthid1,NULL);
pthread_join(pthid2,NULL);
cout << "end join" << endl;
}
void *thmain1(void *arg)
{
for(int i=0; i<50; i++)
{
var = i+1; //线程1改变全局变量的值
printf("thmain1 sleep(%d) var(%d) ok.\n", i+1, var);
sleep(1);
if(i == 5)
{
pthread_cancel(pthid2); //2.在线程1中取消线程2
cout << "cancel pthread2" << endl;
}
}
}
void *thmain2(void *arg) //线程2读出
{
for(int i=0; i<50; i++)
{
printf("thmain2 sleep(%d) var(%d) ok.\n", i+1, var);
sleep(1);
//exit(0); //2. 在子线程调用exit(),将终止整个进程
int* p = new int;
delete p;
//delete p; // 3.重复释放 core;
//if( i == 2) return 0; //可以编译通过
//if( i == 2) return (void *)1; //1.要进行强转,否则编译不通过
if( i == 2) pthread_exit((void *)1);
}
}
线程取消细节
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <iostream>
using namespace std;
//线程id, typedef unsigned long pthread_t
//int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
// void *(*start_routine) (void *), void *arg);
//int pthread_join(pthread_t thread, void **retval);
void *thmain1(void *arg); //线程主函数
int var = 0;
int main()
{
pthread_t thid1=0, thid2=0;
if(pthread_create(&thid1, NULL, thmain1, NULL) != 0) {printf("thid1 faile\n"); exit(-1);}
usleep(100);
pthread_cancel(thid1);
void *ret;
cout << "join..." << endl;
pthread_join(thid1, &ret); //主线程等待子线程退出
printf("thid1 ret=%ld\n", ret);
printf("join ok\n");
//如果这里参打印出400000000可能是线程没有被cancel掉,或者在cancel之前,子线程己运行结束
printf("var=%d\n", var);
}
void *thmain1( void *arg)
{
//设置线程为不可取消状态,上面的pthread_cancel()不起作用,第二个参数是保存线程还有的状态
//pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
//设置线程可以立即取消,而不是延时取消(默认,除非达有一个取消点出现),主线程100微秒后取消线程,var还未执行4亿次,所以var输出不是4亿
//pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,NULL);
for(var=0; var<400000000; var++)
{
;
pthread_testcancel();
//close(2); 用pthread_testcancel()设置取消点
}
return (void*)1;
}
线程退出细节
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <iostream>
#include <string.h>
using namespace std;
//线程退出(终止)状态
//pthread_join可以获得线程退出状态信息
//线程主函数返回void* 表示,可以返回任务信息
/*终止线程的三种方法
1. 子线程主函数中,直接返回,返回值是线程退出码
2. 子线程可以被同一进程中的其他线程调用pthread_cancel()取消
3. 子线程调用pthread_exit()方法
return 与pthread_exit的区别就是,如果在子线程的子函数数中return返回到子线程中
如果在子函数中pthread_exit的话,则子线程退出。
*/
struct st_ret
{
int retcode; //返回码
char retmessage[101]; //返回信息
};
void *thmain1(void *arg);
void *thmain2(void *arg);
int main(int argc, char *argv[])
{
pthread_t thid1=0;
//创建线程
if(pthread_create(&thid1, NULL, thmain1, NULL) != 0) {printf("thid1 faile\n");}
//等待子线程退出
cout << "thmain start..." << endl;
//第二个参数可以获得线程返回信息
//void *pv =0;
//pthread_join(thid1, &pv); //主线程等待子线程退出
//printf("ret = %d\n", pv); //子线程return或者pthread_exit((void*)1)返回的值
struct st_ret *pv = 0;
pthread_join(thid1, (void**)&pv);
printf("retcode = %d, retmessage=%s\n", pv->retcode, pv->retmessage);
delete pv;
cout << "thmain end " << endl;
return 0;
}
void *thmain1( void *arg)
{
printf("thmain1 start...\n");
//return (void *)1150; //线程的返回码
//pthread_exit((void *)1150); //效果同上
//注意,如果用结构体的地址作为线程的返回值,必须保证在线程主函数结束后地址仍然是有效的
//所以,要采用动态分配内存的方法,不能用局部变量。
struct st_ret *st1 = new(struct st_ret);
st1->retcode = 10;
strcpy(st1->retmessage, "pthread1");
return (void *)st1;
}
线程清理细节
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <iostream>
using namespace std;
//线程id, typedef unsigned long pthread_t
//int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
// void *(*start_routine) (void *), void *arg);
//int pthread_join(pthread_t thread, void **retval);
void *thmain1(void *arg); //线程主函数
void thcleanup1(void *arg); //线程清理函数
void thcleanup2(void *arg); //线程清理函数
void thcleanup3(void *arg); //线程清理函数
int main()
{
pthread_t thid1=0, thid2=0;
if(pthread_create(&thid1, NULL, thmain1, NULL) != 0) {printf("thid1 faile\n"); exit(-1);}
//sleep(1);
//pthread_cancel(thid1); //在这里结束子线程,也一样会执行线程清理函数,返回状态为-1
void *ret;
int result = 0;
cout << "join..." << endl;
result = pthread_join(thid1, &ret); //主线程等待子线程退出
printf("thid1 result=%d, ret=%ld\n", result, ret);
printf("join ok\n");
}
void *thmain1( void *arg)
{
pthread_cleanup_push(thcleanup1, NULL); //把线程清理函数入栈,第二个参数是传入线程清理函数的参数
pthread_cleanup_push(thcleanup2, NULL); //把线程清理函数入栈
pthread_cleanup_push(thcleanup3, NULL); //把线程清理函数入栈
//pthread_cleanup_push(thcleanup1, fd); //把线程清理函数入栈,第二个参数是传入线程清理函数的参数
//pthread_cleanup_push(thcleanup2, sockfd); //把线程清理函数入栈(关闭socket)
//pthread_cleanup_push(thcleanup3, &conn); //把线程清理函数入栈(回滚数据库事务)
for(int i=0; i<3; i++)
{
//pthread_cleanup_push(thcleanup1, NULL); //把线程清理函数入栈
sleep(1);
printf("pthmain1 sleep(%d) ok.\n", i+1);
//pthread_cleanup_pop(1); //把线程清理函数出栈 这一对push,pop函数一定要成对出现。可以放在语句块中
//return (void*)1; 在这里结束线程,也会执行线程清理函数。
}
pthread_cleanup_pop(3); //把线程清理函数出栈 参数大于0表示出栈并执行清理函数,=0仅表示出栈
pthread_cleanup_pop(2); //把线程清理函数出栈
pthread_cleanup_pop(1); //把线程清理函数出栈
//return (void*)1;
pthread_exit((void*)1);
}
void thcleanup1(void *arg) //线程清理函数
{
//在这里释放关闭文件、断开网络连接、回滚数据事务、释放锁等
printf("thcleanup1 clean ok\n");
}
void thcleanup2(void *arg) //线程清理函数
{
//在这里释放关闭文件、断开网络连接、回滚数据事务、释放锁等
printf("thcleanup2 clean ok\n");
}
void thcleanup3(void *arg) //线程清理函数
{
//在这里释放关闭文件、断开网络连接、回滚数据事务、释放锁等
printf("thcleanup3 clean ok\n");
}
线程资源的回收
回顾:进程资源的回收 1.子进程退出时,向父进程发送SIGCHLD信号 2.父进程调用wait()函数等待子进程退出,忽略SIGCHLD信号 3.在信号处理函数中释放资源
线程资源回收: 1.线程非分离状态joinable(默认状态) 2.线程分离状态(unjoinable) 3.非分离状态的线程终止时,不会释放线程的全部资源
如果不关心线程退出状态,可以把线程的属性设置为分离,线程结束后,由系统回收资源
1.调用pthread_detach()函数分离线程
2.创建线程前,调用pthread_attr_setdetachstate()设置线程的属性
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <iostream>
using namespace std;
//int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
// void *(*start_routine) (void *), void *arg);
//int pthread_join(pthread_t thread, void **retval);
void *thmain1(void *arg); //线程主函数
void *thmain2(void *arg); //线程主函数
int main()
{
//方法2设置线程分离
pthread_attr_t attr; //申明线程属性的数据结构
pthread_attr_init(&attr); //初始化
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); //设置线程的属性
pthread_t thid1=0, thid2=0;
if(pthread_create(&thid1, &attr, thmain1, NULL) != 0) {printf("thid1 faile\n"); exit(-1);}
pthread_attr_destroy(&attr); //销毁数据结构
//if(pthread_create(&thid2, NULL, thmain2, NULL) != 0) {printf("thid2 faile\n"); exit(-1);}
sleep(10);
void *ret;
int result=0;
cout << "join..." << endl;
//主线程等待子线程退出
result = pthread_join(thid1, &ret); printf("thid1 result=%d,ret=%ld\n", result, ret); //0,1
//result = pthread_join(thid2, &ret); printf("thid2 result=%d,ret=%ld\n", result, ret); //0,2
//再次join会失败
/*
ret=0;
result = pthread_join(thid1, &ret); printf("thid1 result=%d,ret=%ld\n", result, ret); //3,0
result = pthread_join(thid2, &ret); printf("thid2 result=%d,ret=%ld\n", result, ret); //3,0
*/
cout << "join ok. " << endl;
}
void *thmain1( void *arg)
{
//pthread_detach(pthread_self());
for(int i=0; i<3; i++)
{
sleep(1);
printf("pthmain1 sleep(%d) ok.\n", i+1);
}
return (void*)1;
}
void *thmain2( void *arg)
{
pthread_detach(pthread_self()); //设置为分离,则不能再join. 也取不到返回值
for(int i=0; i<5; i++)
{
sleep(1);
printf("pthmain2 sleep(%d) ok.\n", i+1);
}
return (void*)2;
}