05.线程

进程有哪些缺陷?

1.创建的代价较高

进程是OS进行资源分配的基本单位,也就是说创建进程是需要分配资源的,所以创建代价很高

2.通信不方便

进程之间要想进行通信必须借助第三方资源(管道、内存映射、消息队列)

线程的优点有哪些?

线程与进行一样,在单核的情情况下都可以并发执行,多核可以并行执行。
但是线程的创建代价没有进程高,一个进程可以创建多个线程,这写线程共享同一份资源。共享同一份资源自然,通信就方便了很多

pthread_create函数

创建线程的函数

int pthread_create(pthread_t *thread,const pthread_attr_t *attr,(void *)( *start_routine)(void *),void *arg)

参一:传出参数,子线程tid
参二:线程的属性(attr)
参三:函数指针,子进程要执行的代码放在这个函数里面
参四:子进程函数的参数
返回值:
成功返回0
失败返回错误号
#include<stdio.h>
#include<string.h>                                                              
#include<unistd.h>
#include<pthread.h>
#include<fcntl.h>
void* thread1(void* arg){sleep(1);printf("thread1 = %lu\n",pthread_self());return NULL;
}int main(int argc, char* argv[])
{pthread_t tid;int ret = pthread_create(&tid,NULL,thread1,NULL);if(ret == -1){perror("pthread_create error:");return -1;}printf("main therad = %lu\n",pthread_self());//%lu是无符号场整形 unsigned long int while(1);return 0;
}

pthread_self函数

获取线程tid的函数

pthread_t pthread_self(void)

返回值和无符号场整形,%lu
#include<stdio.h>
#include<string.h>                                                              
#include<unistd.h>
#include<pthread.h>
#include<fcntl.h>
#include<sys/stat.h>
int a;
void* thread1(void* arg){printf("thread1 tid = %lu\n",pthread_self());while(a!=10){a++;printf("a = %d\n",a);sleep(1);}return NULL;
}
int main(int argc, char* argv[])
{pthread_t tid;int ret = pthread_create(&tid,NULL,thread1,NULL);if(ret != 0){perror("pthread_create error:");return -1;}printf("main thread tid = %lu\n",pthread_self());while(a!=10){a++;printf("a = %d\n",a);sleep(1);}printf("pthread_create ret = %d\n",ret);return 0;
}

终止线程的方法

1.进程结束了,底下的线程肯定都结束了

在主函数执行return

#include<stdio.h>
#include<string.h>                                                              
#include<unistd.h>
#include<pthread.h>
#include<fcntl.h>
#include<sys/stat.h>
int a;
void* thread1(void* arg){while(a!=10){a++;printf("a = %d\n",a);sleep(1);}return NULL;
}
int main(int argc, char* argv[])
{pthread_t tid;pthread_create(&tid,NULL,thread1,NULL);sleep(1);return 0;
}

调用exit()函数

#include<stdio.h>
#include<string.h>                                                              
#include<unistd.h>
#include<pthread.h>
#include<fcntl.h>
#include<sys/stat.h>
#include<stdlib.h>
int a;
void* thread1(void* arg){while(a!=10){a++;printf("a = %d\n",a);sleep(1);}return NULL;
}
void* thread2(void* arg){sleep(2);exit(-1);return NULL;
}
int main(int argc, char* argv[])
{pthread_t tid;pthread_create(&tid,NULL,thread1,NULL);pthread_create(&tid,NULL,thread2,NULL);while(1);return 0;
}

2.结束当前的线程

在start_rountine函数中执行return

#include<stdio.h>
#include<string.h>                                                              
#include<unistd.h>
#include<pthread.h>
#include<fcntl.h>
#include<sys/stat.h>
#include<stdlib.h>
int a;
void* thread1(void* arg){while(a!=10){a++;printf("a = %d\n",a);return NULL;printf("1\n");}}
int main(int argc, char* argv[])
{pthread_t tid;pthread_create(&tid,NULL,thread1,NULL);sleep(2);return 0;
}

调用pthread_exit()函数

#include<stdio.h>
#include<string.h>                                                              
#include<unistd.h>
#include<pthread.h>
#include<fcntl.h>
#include<sys/stat.h>
#include<stdlib.h>
int a;
void func(){printf("This is func!\n");pthread_exit(NULL);
}
void* thread1(void* arg){while(a!=10){a++;printf("a = %d\n",a);func();printf("1\n");}}
int main(int argc, char* argv[])
{pthread_t tid;pthread_create(&tid,NULL,thread1,NULL);sleep(2);return 0;
}

调用pthread_cancel函数

int pthread_cancel(pthread_t thread);
参一为要取消的线程
函数描述:调用该函数之后,会向指定线程发送一个取消请求,然后立即返回,被请求取消的进程需要等到某个取消点(通常为系统调用)
可以调用pthread_testcancel()函数,手动创建取消点
#include<stdio.h>
#include<string.h>                                                              
#include<unistd.h>
#include<pthread.h>
#include<fcntl.h>
#include<sys/stat.h>
#include<stdlib.h>
int a;
int stats;void* thread1(void* arg){while(1){if(a == 10){a=0;}a++;pthread_testcancel();}
}
int main(int argc, char* argv[])
{pthread_t tid;pthread_create(&tid,NULL,thread1,NULL);int ret = pthread_cancel(tid);if(ret == 0){printf("cancel sucess!\n");}else{printf("cancel error!\n");}while(1){printf("a = %d\n",a);sleep(1);}return 0;
}

线程的连接和分离

pthread_join函数

函数原型:int pthread_join(pthread_t tid ,void **retval);

函数描述:等待指定线程的结束,然后回收,这种操作被称为连接。未连接的进程会产生僵尸线程

#include<stdio.h>
#include<string.h>                                                              
#include<unistd.h>
#include<pthread.h>
#include<fcntl.h>
#include<sys/stat.h>
#include<stdlib.h>
int a;void* thread1(void* arg){while(1){if(a == 10){pthread_exit(NULL);}a++;}
}
int main(int argc, char* argv[])
{pthread_t tid;void* res;pthread_create(&tid,NULL,thread1,NULL);pthread_join(tid,&res);printf("res = %s",(char*)res);printf("a = %d\n",a);return 0;
}

有些线程不关心返回状态,只是希望OS能在线程终止的时候自动清理并移出,这时可以调用pthread_detach函数设置线程未分离状态

pthread_detach函数

#include<stdio.h>
#include<string.h>                                                              
#include<unistd.h>
#include<pthread.h>
#include<fcntl.h>
#include<sys/stat.h>
#include<stdlib.h>
int a;void* thread1(void* arg){while(1){if(a == 10){pthread_exit(NULL);}a++;}
}
void* thread2(void* arg){while(1){if(a == 10){pthread_exit(NULL);}a++;}
}
int main(int argc, char* argv[])
{pthread_t tid1;pthread_t tid2;void* res;pthread_create(&tid1,NULL,thread1,NULL);pthread_create(&tid2,NULL,thread2,NULL);pthread_detach(tid2);pthread_join(tid2,&res);printf("res = %s",(char*)res);printf("a = %d\n",a);return 0;
}

练习

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

#include<stdio.h>
#include<string.h>                                                              
#include<unistd.h>
#include<pthread.h>
#include<fcntl.h>
#include<sys/stat.h>
#include<stdlib.h>
const int N=1e6;
int a;
void* thread1(void* arg){for(int i = 1;i <= N; i++){a++;}
}
int main(int argc, char* argv[])
{pthread_t tids[10];//创建10个线程,用tids数组存储tidfor(int i = 0;i < 10; i++){pthread_create(tids+i,NULL,thread1,NULL);}//阻塞等待10个线程都执行结束,打印a的值for(int i = 0;i < 10; i++){pthread_join(tids[i],NULL);}printf("a = %d\n",a);return 0;
}

观察数据

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

线程同步的引入

观察上面的数据,发现10个线程如果同时执行1e6次自增操作,最后结果应该是1e7,但是多次得到的结果确实小于等于1e7,这种情况是不可以接受的,为什么会出现这种问题?

因为线程之间的并发执行的,且a++不是原子操作。
举一个例子,现在线程1和线程2并发执行,它们同时读取了a的数据,读到的都是5,然后对5+1返回结果给a,线程1和线程2同时结束,a的值为6,而不是7,这就出现了问题。出现这个问题的原因是线程之间是共享资源的,同时访问一块内存,有时会造成错误。(保证线程和线程访问同一块空间的时候不出现冲突)
所以得让进程之间商量着来,协同一下步调。

同步

同步分为同步异步的同步和线程同步

同步与异步

提到同步和异步,很难不想到阻塞和非阻塞。

阻塞和非阻塞一半表述进程的状态,具体指的是进程在执行过程中是否遇到阻塞实现(是否被挂起),如果被挂起了就是阻塞状态,没有被挂起就是非阻塞

而同步异步一般指的是系统调用时候是否会阻塞执行

同步函数

同步函数是指在系统调用的过程中,程序会被阻塞,知道系统调用结束返回结果。
特点:
1.阻塞执行
2.可预测,符合传统程序的执行过程

异步函数

异步函数指的是系统调用过程中,程序不会阻塞,继续执行后面的代码。等到系统调用结束之后,内核会通过某种机制(信号或者回调函数等等)通知程序。
特点:
1.非阻塞:不会阻塞等待返回的结果,而是直接执行后面的代码。
2.事件驱动性:当系统调用完成时,内核会通过事件通知应用程序,应用程序需要处理这些事件
3.复杂性:异步编程模型复杂,需要处理多个事件和状态

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/9723.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

大模型日报2024-05-10

大模型日报 2024-05-10 大模型资讯 阿里巴巴发布新AI语言模型Qwen2.5&#xff0c;超越OpenAI的GPT-4 摘要: 阿里巴巴集团旗下的阿里云推出了新型大型语言模型Qwen2.5。据称&#xff0c;在语言生成能力上超过了OpenAI的GPT-4&#xff0c;尽管在其他领域也有出色表现。该模型的发…

JAVA大量数据导出excel

背景&#xff1a;因项目需要导出3万行&#xff0c;90列的数据到excel&#xff0c;使用传统的apache poi 直接导出&#xff0c;导致504连接超时无法导出。然后改造方法&#xff0c;异步导出。 一、准备一个导出类&#xff0c;属性有id&#xff0c;outputstrream,finleName,err,e…

[debian12] wps for linux打开PDF卡死

原因 wps使用wpspdf处理PDF文件&#xff0c;而wpspdf依赖于libtiff5.so.5。而系统更新后&#xff0c;linux发行版提供的是libtiff.so.6或更新版本&#xff0c;导致其无法正常工作。 解决方案 理论上&#xff0c;安装libtiff5即可&#xff1a; apt install libtiff5.so.5 但实…

VM虚假机联网(无代码,超简单)NAT模式

1、左边顶上编辑里面最下面找到虚拟网络编辑器2.启用管理员特权3.重新创建一个NAT模式的网络&#xff08;名称随便一个&#xff09; 4.打开这两个设置里面的东西进行拍照并记住IP区间和网关&#xff0c;等下要用&#xff1b; 5.打开虚拟机&#xff0c;右上角&#xff0c;下标点…

腾讯云服务器部署前后端服务

服务器&#xff1a;OpenCloudOS &#xff08;兼容centos8&#xff09; 后端&#xff1a;javaSpringboot 前端&#xff1a;Vue 下载jdk 1&#xff09;下载jdk11 wget https://download.java.net/openjdk/jdk11/ri/openjdk-1128_linux-x64_bin.tar.gz 2&#xff09;解压jdk …

论文研读 Disentangled Information Bottleneck

解耦信息瓶颈 摘要&#xff1a; 信息瓶颈方法是一种从源随机变量中提取与预测目标随机变量相关的信息的技术&#xff0c;通常通过优化平衡压缩和预测项的IB拉格朗日乘子f来实现&#xff0c;然而拉格朗日乘子很难优化&#xff0c;需要多次实验来调整拉格朗日乘子的值&#xff0c…

使用leafletjs实现地图洋流、风场气象6要素地图标注、等值面图

前期实现的功能由于数据失效无法显示效果&#xff0c;今天重新对接一个数据源进行展示&#xff0c;实现效果如下图&#xff1a; 访问地址&#xff1a;可视化三维 GIS 特效 - 沉浸式视觉体验呈现令人惊叹的三维 GIS 特效&#xff0c;提供沉浸式视觉体验。https://www.wheart.cn/…

QAnything 在mac M2 上纯python环境安装使用体验(避坑指南)

这是一篇mac m2本地纯python环境安装 qanything的文章。安装并不顺利&#xff0c;官方提供的模型无法在本地跑。 这篇文章记录了&#xff0c;使用xinference来部署本地模型&#xff0c;并利用openAi的通用接口的方式&#xff0c;可以正常使用。 记录了遇到的所有的问题&#xf…

*****水上飞机:继承,虚函数,虚继承

一题目 请设计以下航行器、飞机、船、水上飞机等 4 个类。 CRAFT 为航行器类&#xff0c;是公共基类&#xff0c;提供航行器的基本特性。包括&#xff1a; 一个保护数据成员&#xff1a;speed(速度)。 三个公有成员函数&#xff1a;构造函数(初始化速度)、析构函数和 Show 函数…

AOSP开发

Android 开发者 | Android Developers (google.cn) android开源代码&#xff1a; Android 开源项目 | Android Open Source Project (google.cn)

FreeRTOS任务调度器

目录 1、什么是任务调度器 2、FreeRTOS中的任务调度器 2.1 抢占式调度 2.2 时间片调度 2.3 协作式调度 3、任务调度案例分析 3.1 实验需求 3.2 CubeMX配置 3.3 代码实现 3.3.1 uart.c 重定向printf 3.3.2 打开freertos.c并添加代码 3.3.4 代码现象 1、什么是任务调度…

Spring:spring-boot-starter-parent与spring-boot-dependencies的区别

参考&#xff1a;spring-boot-starter-parent与spring-boot-dependencies的区别

[uniapp] 配置ts类型声明

我想引进图片,但是报错 声明一下就行 TypeScript 支持 | uni-app官网 创建tsconfig.json文件,复制官网的配置 然后在随便一个目录下写一个随便名字的.d.ts文件 例如这样 保存就行 因为ts是默认扫描全部的,所以要按照官网的写法 把不必要的排除掉就行,免得浪费性能

JS-导入导出

export和export default是ES6中导出模块中变量的语法 导入导出变量 //导出方法&#xff08;js文件中&#xff09; export const 变量名值//导入方法 对应导入的变量&#xff0c;一定要加花括号 import {变量名} from js文件路径 导入导出函数 //导出方法&#xff08;js文件中…

RST文档技巧汇总

RST文件技巧汇总 前言转换工具简洁语法注释空行标题与章节样式链接图片列表表格代码块文档内引用引用rst 前言 RST全称ReStructuredText&#xff0c;是一种使用简单标记语法编写文档的文本文件格式。RST文档是轻量级标记语言的一种&#xff0c;被设计为容易阅读和编写的纯文本…

TikTok自动评论、回复的脚本怎么制作?

在当今数字化的时代&#xff0c;社交媒体平台如TikTok已经成为人们日常生活的一部分&#xff0c;为了更有效地在TikTok上进行营销或互动&#xff0c;许多用户和企业开始寻找自动化工具&#xff0c;如自动评论和回复的脚本&#xff0c;以节省时间并提高效率。 本文将科普如何制…

[数据结构]——非递归排序总结——笔试爱考

具体代码实现在gitee&#xff1a;登录 - Gitee.com 目录 具体代码实现在gitee&#xff1a;登录 - Gitee.com 1.非递归实现的快速排序算法。 第一步 首先要创建一个栈 第二步紧接着进行入栈&#xff0c;出栈&#xff0c;弹出栈顶元素&#xff0c;获取栈顶元素&#xff0c;判…

Windows下安装Node.js、npm和electronic,并运行一个Hello, World!脚本程序

20240510 By wdhuag 目录 简介&#xff1a; 参考&#xff1a; 安装Node.js 安装npm 配置npm&#xff1a; 修改包存放目录和缓存目录 切换镜像源 使用 nrm 切换镜像源 安装Electron 运行一个Hello, World!脚本程序 安装Yarn JavaScript 指南 简介&#xff1a; Nod…

英文论文审稿

英文论文审稿1 英文论文审稿4英文论文审稿5审稿意见: Identification and early warning method of key disaster-causing factors of AE signals for rockburst based on principal component analysis method 作者从城市地质环境的量化评价出发,创造性地提出城市地质环境健…

MT8370_联发科MTK8370(Genio 510)芯片性能规格参数

MT8370芯片是一款利用超高效的6nm制程工艺打造的边缘AI平台&#xff0c;具有强大的性能和功能。这款芯片集成了六核CPU(2x2.2 GHz Arm Cortex-A78 & 4x2.0 GHz Arm Cortex-A55)、Arm Mali-G57 MC2 GPU、集成的APU(AI处理器)和DSP&#xff0c;以及一个HEVC编码加速引擎&…