
Linux-线程终止-线程等待-线程分离-线程安全
验证:
如果主线程自己取消自己,调用pthread_cancel(pthread_self),那么主线程的状态变为僵尸状态(Z),工作线程正常,整个进程没有退出。
thread:需要等待的线程的标识符 retval:线程退出时的返回值
发布日期:2021-05-08 20:30:30
浏览次数:22
分类:精选文章
本文共 7196 字,大约阅读时间需要 23 分钟。
文章目录
1. 线程终止
1.1 pthread_exit函数
作用: 谁调用谁退出
参数: retval:线程A结束的时候传递给等待线程B的参数 验证:#include#include #include #define a 4 struct ThreadId{ int thread_id_;}; void* MyThreadStart(void* arg) { struct ThreadId* ti = (struct ThreadId*)arg; printf("i am MyThreadStart, i = %d\n", ti->thread_id_); sleep(1); pthread_exit(NULL); printf("pthread_exit, i = %d\n", ti->thread_id_); delete ti; }int main(){ pthread_t tid; for(int i = 0; i < a; i++) { struct ThreadId* ti = new ThreadId(); ti->thread_id_ = i; int ret = pthread_create(&tid,NULL,MyThreadStart,(void*)ti); if(ret < 0) { perror("pthread_create"); return 0; } } //创建成功 while(1) { printf("i am main thread\n"); sleep(1); } return 0; }
1.2 线程的入口函数代码执行完毕,线程退出
1.3 pthread_cancel函数
功能: 根据线程的标识符终止对应线程
参数: thread:被终止的线程的标识符 获取自己的线程标识符: pthread_t pthread_self(void);
#include#include #include #define THREAD_NUM 4 struct ThreadId { int thread_id_; }; void* MyThreadStart(void* arg) { struct ThreadId* ti = (struct ThreadId*)arg; //while(1) { printf("i am MyThreadStart, i = %d\n", ti->thread_id_); sleep(1); } pthread_cancel(pthread_self()); delete ti; } int main(){ pthread_t tid[THREAD_NUM]; for(int i = 0; i < THREAD_NUM; i++) { struct ThreadId* ti = new ThreadId(); ti->thread_id_ = i; int ret = pthread_create(&tid[i], NULL, MyThreadStart, (void*) ti); if(ret < 0) { perror("pthread_create"); return 0; } } //pthread_cancel(pthread_self()); while(1) { printf("i am main thread\n"); sleep(1); } return 0;}

验证:
#include#include #include #define THREAD_NUM 4 struct ThreadId{ int thread_id_;};void* MyThreadStart(void* arg){ struct ThreadId* ti = (struct ThreadId*)arg; while(1) { printf("i am MyThreadStart, i = %d\n", ti->thread_id_); sleep(1); } delete ti;}int main(){ pthread_t tid[THREAD_NUM]; for(int i = 0; i < THREAD_NUM; i++) { struct ThreadId* ti = new ThreadId(); ti->thread_id_ = i; int ret = pthread_create(&tid[i], NULL, MyThreadStart, (void*)ti); if(ret < 0) { perror("pthread_create"); return 0; } } pthread_cancel(pthread_self()); while(1) { printf("i am main thread\n"); sleep(1); } return 0;}

2. 线程等待
2.1 原因
由于线程的默认属性为joinable属性,当线程退出的时候其资源不会被操作系统回收,需要其他线程来进行进程等待,继续回收,否则就会造成内存泄露。
2.2 接口
int pthread_join(pthread_t thread, void **retval);

1.线程入口函数退出的时候,retval就是线程入口函数的返回值
2.pthread_exit(void* retval),retval就是pthread_exit函数的参数值 3.pthread_cancel:retval的值是一个常数PTHREAD_CANCELED,调用pthread_join函数进行等待的执行流如果还没有等待到退出的线程,则当前调用pthread_join函数的执行流就会阻塞。2.3 验证
#include#include #include #define THREAD_NUM 4 struct ThreadId { int thread_id_; }; void* MyThreadStart(void* arg) { struct ThreadId* ti = (struct ThreadId*)arg; while(1) { printf("i am MyThreadStart, i = %d\n", ti->thread_id_); sleep(1); } delete ti; return NULL; } int main(){ pthread_t tid[THREAD_NUM]; for(int i = 0; i < THREAD_NUM; i++) { struct ThreadId* ti = new ThreadId(); ti->thread_id_ = i; int ret = pthread_create(&tid[i], NULL, MyThreadStart, (void*)ti); if(ret < 0) { perror("pthread_create"); return 0; } } for(int i = 0; i < THREAD_NUM; i++) { pthread_join(tid[i], NULL); } while(1) { printf("i am main thread\n"); sleep(1); } return 0;}

3. 线程分离
3.1 概念
一个进程的属性如果从joinable属性变成detach属性,则当前这个线程在退出的时候,不需要其他线程回收资源,操作系统会自己回收资源。
3.2 接口
参数: pthread_t thread
如果工作线程自己分离自己,要写在工作线程代码的最前面。3.3 验证
#include#include #include #define THREAD_NUM 4struct ThreadId{ int thread_id_;}; void* MyThreadStart(void* arg){ pthread_detach(pthread_self()); struct ThreadId* ti = (struct ThreadId*)arg; //while(1) { printf("i am MyThreadStart, i = %d\n", ti->thread_id_); sleep(1); } delete ti; return NULL;}int main(){ pthread_t tid[THREAD_NUM]; for(int i = 0; i < THREAD_NUM; i++) { struct ThreadId* ti = new ThreadId(); ti->thread_id_ = i; int ret = pthread_create(&tid[i], NULL, MyThreadStart, (void*)ti); if(ret < 0) { perror("pthread_create"); return 0; } } while(1) { printf("i am main thread\n"); sleep(1); } return 0; }
4. 线程安全
4.1 概念
多个执行流,访问临界资源,不会导致程序产生二义性。
执行流: 理解为线程 访问: 指的是对临界资源进行操作 临界资源: 指的是多个线程都可以访问到的资源 例如:全局变量,某个结构体变量,某个类的实例化指针 临界区: 代码操作临界资源的代码区域称之为临界区 二义性: 结果会有多个4.2 原理
4.3 线程不安全的现象
内存中我们有一个i = 10,我们假设有两个线程,两个线程都是对于i进行加1操作。线程1先开始执行,当线程1把i读到寄存器后,由于计算机是分时轮转,这时候时间片用完了,线程1被切换出去了,此时线程1在寄存其中i的值是10,之后线程2被切换进来了,线程2从内存当中读到i的值为10,经过CPU进行运算,写回到寄存器,寄存器再存到内存当中,这时候i在内存当中的值被修改为了11,线程2结束后,线程1又被切换回来了,线程1通过保存的上下文信息知道i此时的值是10,通过程序计数器知道要在CPU当中进行加1操作,经过CPU进行运算,写回到寄存器,寄存器再存到内存当中,这时候i在内存当中的值仍然是11,但是实际上我们对i执行了两次加1操作,正确的值是12,这时候代码的结果就存在了二义性。
4.4 验证
#include#include #include #define THREAD_NUM 2int g_tickets = 10;void* MyThreadStart(void* arg){ while(1) { if(g_tickets > 0) { printf("i have %d, i am %p\n", g_tickets, pthread_self()); g_tickets--; } else { pthread_exit(NULL); } } return NULL;}int main(){ pthread_t tid[THREAD_NUM]; for(int i = 0; i < THREAD_NUM; i++) { int ret = pthread_create(&tid[i], NULL, MyThreadStart, NULL); if(ret < 0) { perror("pthread_create"); return 0; } } for(int i = 0; i < THREAD_NUM; i++) { pthread_join(tid[i], NULL); } printf("pthread_join end...\n"); return 0;}
发表评论
最新留言
第一次来,支持一个
[***.219.124.196]2025年03月21日 10时58分45秒
关于作者

喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
数据仓库建模方法论
2021-05-09
虚拟机搭建hadoop环境
2021-05-09
DataStax Bulk Loader教程(四)
2021-05-09
.NET应用框架架构设计实践 - 概述
2021-05-09
Rust 内置 trait :PartialEq 和 Eq
2021-05-09
Hibernate(十四)抓取策略
2021-05-09
[菜鸟的设计模式之旅]观察者模式
2021-05-09
Spring-继承JdbcDaoSupport类后简化配置文件内容
2021-05-09
Java基础IO流(一)
2021-05-09
Hibernate入门(四)---------一级缓存
2021-05-09
MySQL事务(学习笔记)
2021-05-09
一个web前端开发者的日常唠叨
2021-05-09
内存分配-slab分配器
2021-05-09
技术写作技巧分享:我是如何从写作小白成长为多平台优秀作者的?
2021-05-09
Jupyter Notebook 暗色自定义主题
2021-05-09
[Python学习笔记]组织文件
2021-05-09
基于Redo Log和Undo Log的MySQL崩溃恢复流程
2021-05-09
从RocketMQ的Broker源码层面验证一下这两个点
2021-05-09
如何正确的在项目中接入微信JS-SDK
2021-05-09
纵览全局的框框——智慧搜索
2021-05-09