线程---多线程--互斥--条件变量--生产消费模型

概念

线程是进程内部的执行分支,是CUP调度的基本单位
进程=内核数据结构+进程代码和数据

线程的理解:

产生的原因:
我们的代码在进程中是串行运行的,如果我们想要使他并行运行,分别完成不同的任务。之前的做法的创建子进程。但是创建子进程不仅要创建进程的PCB,内核数据结构也要创建。对资源的消耗较大,所以我们是不是可以创建一些只创建PCB,让他们共享同一块内核数据结构和代码呢?
就这样我们的线程产生了。
但是如果单独的设计出线程结构,来让OS管理,这又是非常复杂的过程,所以linux设计者发现,线程和进程有很高的相似性,所以是不是可以用进程来模拟线程呢?
在这里插入图片描述
所以之后我们对进程的理解:站在内核角度:承担分配系统资源基本实体

进程vs线程

之前我们所说的进程,今天我们看来只是进程的一种特殊情况:内部只有一个线程的进程
在这里插入图片描述
那么之前所说的进程调度,因为线程是用进程来模拟的,所以进程调度其实就是线程调度。但是线程也是可以访问它所属进程的共享资源的,所以这样说也不准确。所以我们现在把调度成为轻量级进程的调度。
在这里插入图片描述
LWP,是线程的id,所以调度的基本单位是LWP

页表深层理解

多执行流=线程+独属于它的代码——>线程<=多执行流<=进程

我们创建线程,就是希望执行多执行流分支运行,但是多执行流又是如何进行代码划分的呢?
这样我们就不得不重谈一下地址空间和页表了:
如果按照我们之前理解的页表:
在这里插入图片描述
所以页表的结构是这样的
在这里插入图片描述
在这里插入图片描述

线程控制

铺垫:
通过对linux线程的认识我们知道,在linux中准确来说是没有线程这个概念的,只有轻量级进程,所以是没有线程的系统调用接口的,但是用户是不知道的,所以我们要在系统外的用户层装一个原生线程库,共用户调用接口来控制线程:
在这里插入图片描述
线程的创建:
在这里插入图片描述
在这里插入图片描述
线程id:
pthread_self()
在那个线程内执行这个函数就得到那个线程的id,每个线程都是唯一的
在这里插入图片描述

线程等待:
主线程退出,代表进程退出,那么进程所申请的所有资源也就退出了,———》那么新进程不管运行完没完也要退出
在这里插入图片描述
所以我们往往需要主线程最后结束,线程等待:线程也要被等待,不然会产生进程哪里的内存泄漏。
线程等待:
pthread_join(tid,**retvl)
在这里插入图片描述

在这里插入图片描述
线程退出:
1、代码跑完,结果对
2、代码跑完,结果不对
3、出异常了
其中1 2两点结果的对不对可以通过pthread_join(tid,**retvl)中的输出型参数retvl获得

线程出异常:
多线程中任何一个因为异常退出,整个进程就会退出,所以主线程根本不用获取新线程的异常退出信息,因为他根本就没机会就都退出了。——
信号是进程的信号,所以是所有线程共享的信号三表。
在这里插入图片描述

在这里插入图片描述

线程重要理论:

线程的优点:
1、创建一个新线程比创建一个新进程代价要小的多——创建进程要创建他的地址空间内核数据结构
2、与进程之间的切换相比,线程之间的切换需要操作系统做的工作要少很多
在这里插入图片描述
3、线程占用的资源要比进程少很多
4、能充分利用多处理器的可并行数量
5、在等待慢速I/O操作结束的同时,程序可执行其他的计算任务
6、计算密集型应用,为了能在多处理器系统上运行,将计算分解到多个线程中实现
7、I/O密集型应用,为了提高性能,将I/O操作重叠。线程可以同时等待不同的I/O操作。

线程私有:
1、线程的硬件上下文(CUP寄存器值)调度
2、线程的独立栈结构

线程共享:
1.代码和全局数据
2、进程文件描述符

多线程中如果功函数被多个线程同时进入——该函数被重入了

线程的传参:
在这里插入图片描述
C++语言的多线程
c++语言也有创建线程的函数
在这里插入图片描述
这样就可以实现语言的跨平台性。

线程的tid

我们创建线程的时候都会得到一个id,
在这里插入图片描述

为什么不一样呢?
在这里插入图片描述
线程局部存储和全局变量
如果在每个线程的代码中定义同一个变量名的变量,他们是没有任何关系的,两者都有不同的地址,互不干扰:
在这里插入图片描述
如果是全局变量的话,所有的线程可以修改,
在这里插入图片描述
如果想要把全局变量变为线程的局部储存变量的话
在这里插入图片描述

分离线程

在这里插入图片描述
在这里插入图片描述

主线程等待新线程pthread_join,是阻塞等待的,以等待就不能干自己的事了。但是不等待又会出问题,随意如果我们不需要关心新线程的返回结果时,就可以用
pthrad_detach(tid)来分离线程
在这里插入图片描述
注意:分离并不是把这个线程真的分离出进程,分离的作用只是不用等待。
其他线程的特性任然要遵循
且如果是分离的,那么主线程就一定要最后退出,就比如我们用的大部分软件,只要你不退出,那么就一直死循环的运行的。——这样的进程也叫常住进程
在这里插入图片描述

线程锁

如果多个线程都可以对某个共享资源做修改,且修改这个共享资源的过程不是原子,那么就会造成数据不一致的情况:
demo:用多个线程抢票的例子演示:
在这里插入图片描述
这样的并发访问导致数据不一致的问题本质是多执行流访问全局变量导致的,想要避免这样的问题,那么我们就要把全局变量保护起来(临界资源),把临界资源通过临界区保护起来
产生临界区可以通过加锁的方式:
在这里插入图片描述
具体实现:
在这里插入图片描述
锁是什么:
在这里插入图片描述
这样的方式还是有不足之处,如果一个刚申请了锁的进程再他解锁后,锁有被他抢去了的话,就会造成其他线程饥饿的问题
在这里插入图片描述
那么我们如何避免这种情况的发生呢?
在这里插入图片描述
条件变量的相关接口:
在这里插入图片描述
一个demo
创建一个主线程,主要工作时隔一段时间就唤醒唤醒一个在条件变量等待队列中的一个线程
创建5个线程,开始的时候去争抢临界区的锁,进入临界区后马上进入条件变量的等待队列中。等待被叫醒后执行之后的操作。

#include <iostream>
#include <string>
#include <vector>
#include <pthread.h>
#include <unistd.h>pthread_cond_t gcond = PTHREAD_COND_INITIALIZER; // 条件变量
pthread_mutex_t gmutex = PTHREAD_MUTEX_INITIALIZER; // 互斥锁void *SlaverCore(void *args)
{std::string name = static_cast<const char *>(args);while (true){// 1. 加锁pthread_mutex_lock(&gmutex);// 2. 一般条件变量是在加锁和解锁之间使用的pthread_cond_wait(&gcond, &gmutex); // gmutex:这个是,是用来被释放的[前一半]std::cout << "当前被叫醒的线程是: " << name << std::endl;// 3. 解锁pthread_mutex_unlock(&gmutex);}
}void *MasterCore(void *args)
{sleep(3);std::cout << "master 开始工作..." << std::endl;std::string name = static_cast<const char *>(args);while (true){pthread_cond_signal(&gcond);// 唤醒其中一个队列首部的线程//pthread_cond_broadcast(&gcond);// 唤醒队列中所有的线程std::cout << "master 唤醒一个线程..." << std::endl;sleep(1);}
}void StartMaster(std::vector<pthread_t> *tidsptr)
{pthread_t tid;int n = pthread_create(&tid, nullptr, MasterCore, (void *)"Master Thread");//创建一个主控制线程if (n == 0){std::cout << "create master success" << std::endl;}tidsptr->emplace_back(tid);
}void StartSlaver(std::vector<pthread_t> *tidsptr, int threadnum = 3)
{for (int i = 0; i < threadnum; i++){char *name = new char[64];snprintf(name, 64, "slaver-%d", i + 1); // thread-1pthread_t tid;int n = pthread_create(&tid, nullptr, SlaverCore, name);if (n == 0){std::cout << "create success: " << name << std::endl;tidsptr->emplace_back(tid);}}
}void WaitThread(std::vector<pthread_t> &tids)
{for (auto &tid : tids){pthread_join(tid, nullptr);}
}int main()
{std::vector<pthread_t> tids;StartMaster(&tids);StartSlaver(&tids, 5);WaitThread(tids);return 0;
}

执行结果:每个线程都能较为公平的次数执行
在这里插入图片描述

生产消费模型——理解锁和条件变量

在这里插入图片描述
代码:
1、创建两批线程
一批生产线程,去执行生产的那个函数,一批消费的去执行消费的那个函数
且他们传参的时候共享资源是那个阻塞队列
在这里插入图片描述
生产和消费都是去改变我们传参的队列的,所以我们要去队列的代码中把插入函数和出队列函数设置为临界区
在这里插入图片描述
如果2有3个消费者一个生产者,且生产者没一秒值2生产一个,那么所有的消费者都会进入等待线程
然后到之后生产者生产一个,消费者消费一个(反之也一样)——同步
在这里插入图片描述
在这里插入图片描述
总代码见:添加链接描述
意义:消费者拿到任务后,可以多线程并发执行

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

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

相关文章

深入解析kube-scheduler的算法自定义插件

目录 ​编辑 一、问题引入 二、自定义步骤 三、最佳实践考虑 一、问题引入 当涉及到 Kubernetes 集群的调度和资源分配时&#xff0c;kube-scheduler 是一个关键组件。kube-scheduler 负责根据集群的调度策略&#xff0c;将 Pod 分配到适当的节点上。kube-scheduler 默认使…

cn.hutool.poi.excel 实现excel导出效果 首行高度,行样式,颜色,合并单元格,例子样式

需求 接了需求&#xff0c;下载excel模版&#xff0c;本来看着还是简单的&#xff0c;然后实现起来一把泪&#xff0c;首先是使用poi&#xff0c;我查了好久&#xff0c;才实现&#xff0c;然后是我用easyexcel又实现了一遍&#xff0c;用了一个周多才实现。 这是需求&#x…

web前端学习笔记11

11. CSS3高级特效 11.1 CSS3变形 CSS3变形是一些效果的集合, 如平移、旋转、缩放、倾斜效果 每个效果都可以称为变形(transform),它们可以分别操控元素发生平移、旋转、缩放、倾斜等变化 语法 transform:[transform-function] ; /* 设置变形函数,可以是一个,也可以是多…

python:__class_getitem__使用以及cached_property源码分析

python&#xff1a;__class_getitem__使用以及cached_property源码分析 1 前言 Python中如何模拟泛型类型&#xff1f; 当使用类型标注时&#xff0c;使用 Python 的方括号标记来形参化一个 generic type 往往会很有用处。 例如&#xff0c;list[int] 这样的标注可以被用来表…

如何通过OpenHarmony的音频模块实现录音变速功能?

简介 OpenAtom OpenHarmony&#xff08;以下简称“OpenHarmony”&#xff09;是由开放原子开源基金会孵化及运营的开源项目&#xff0c;是面向全场景、全连接、全智能时代的智能物联网操作系统。 多媒体子系统是OpenHarmony系统中的核心子系统&#xff0c;为系统提供了相机、…

Python语法学习之 - 生成器表达式(Generator Expression)

第一次见这样的语法 本人之前一直是Java工程师&#xff0c;最近接触了一个Python项目&#xff0c;第一次看到如下的代码&#xff1a; i sum(letter in target_arr for letter in source_arr)这条语句是计算source 与 target 数组中有几个单词是相同的。 当我第一眼看到这样…

Offline RL : Beyond Reward: Offline Preference-guided Policy Optimization

ICML 2023 paper code preference based offline RL&#xff0c;基于HIM&#xff0c;不依靠额外学习奖励函数 Intro 本研究聚焦于离线偏好引导的强化学习&#xff08;Offline Preference-based Reinforcement Learning, PbRL&#xff09;&#xff0c;这是传统强化学习&#x…

js二进制数据,文件---ArrayBuffer,二进制数组

1.二进制数据 在 JavaScript 中有很多种二进制数据格式&#xff0c;比如&#xff1a;ArrayBuffer&#xff0c;Uint8Array&#xff0c;DataView&#xff0c;Blob&#xff0c;File 及其他。 2.ArrayBuffer 基本的二进制对象是 ArrayBuffer —— 对固定长度的连续内存空间…

linux:信号深入理解

文章目录 1.信号的概念1.1基本概念1.2信号的处理基本概念1.3信号的发送与保存基本概念 2.信号的产生2.1信号产生的五种方式2.2信号遗留问题(core,temp等) 3.信号的保存3.1 信号阻塞3.2 信号特有类型 sigset_t3.3 信号集操作函数3.4 信号集操作函数的使用 4.信号的处理4.1 信号的…

Qt输入输出类使用总结

Qt输入输出类简介 QTextStream 类(文本流)和 QDataStream 类(数据流)Qt 输入输出的两个核心类,其作用分别如下: QTextStream 类:用于对数据进行文本格式的读/写操作,可在 QString、QIODevice或 QByteArray 上运行,比如把数据输出到 QString、QIODevice 或 QByteArray 对象…

Ubuntu切换内核版本

#安装内核安装工具 sudo apt-get install software-properties-common sudo add-apt-repository ppa:cappelikan/ppa sudo apt-get update sudo apt-get install mainline#安装指定内核版本(有些版本并不能安装成功) mainline install 5.14.10#更新GRUB配置 sudo update-grub#查…

Python实现将LabelMe生成的JSON格式转换成YOLOv8支持的TXT格式

标注工具 LabelMe 生成的标注文件为JSON格式&#xff0c;而YOLOv8中支持的为TXT文件格式。以下Python代码实现3个功能&#xff1a; 1.将JSON格式转换成TXT格式&#xff1b; 2.将数据集进行随机拆分&#xff0c;生成YOLOv8支持的目录结构&#xff1b; 3.生成YOLOv8支持的YAML文件…

操作教程|通过DataEase开源BI工具对接金山多维表格

前言 金山多维表格是企业数据处理分析经常会用到的一款数据表格工具&#xff0c;它能够将企业数据以统一的列格式整齐地汇总至其中。DataEase开源数据可视化分析工具可以与金山多维表格对接&#xff0c;方便企业更加快捷地以金山多维表格为数据源&#xff0c;制作出可以实时更…

【网络版本计算器的实现】

本章重点 理解应用层的作用, 初识HTTP协议理解传输层的作用, 深入理解TCP的各项特性和机制对整个TCP/IP协议有系统的理解对TCP/IP协议体系下的其他重要协议和技术有一定的了解学会使用一些分析网络问题的工具和方法 ⭐注意!! 注意!! 注意!! 本课是网络编程的理论基础.是一个服务…

Antd Vue项目引入TailwindCss之后出现svg icon下移,布局中的问题解决方案

目录 1. 现象&#xff1a; 2. 原因分析&#xff1a; 3. 解决方案&#xff1a; 写法一&#xff1a;扩展Preflight 写法二&#xff1a; 4. 禁用 Preflight 1. 现象&#xff1a; Antd Vue项目引入TailwindCss之后出现svg icon下移&#xff0c;不能对齐显示的情况&#xff0…

爬虫实训案例:中国大学排名

近一个月左右的时间学习爬虫&#xff0c;在用所积累的知识爬取了《中国大学排名》这个网站&#xff0c;爬取的内容虽然只是可见的文本&#xff0c;但对于初学者来说是一个很好的练习。在爬取的过程中&#xff0c;通过请求数据、解析内容、提取文本、存储数据等几个重要的内容入…

React-router 最佳实践

使用的是 BrowserRouter&#xff0c;Routes 和 Route&#xff0c;这是 react-router-dom v5 和 v6 都支持的 API。这种方式的优点是路由配置和应用的其它部分是紧密集成的&#xff0c;这使得路由配置更加直观和易于理解 // router/index.js import { BrowserRouter as Router,…

【Qt 学习笔记】Qt常用控件 | 布局管理器 | 网格布局Grid Layout

博客主页&#xff1a;Duck Bro 博客主页系列专栏&#xff1a;Qt 专栏关注博主&#xff0c;后期持续更新系列文章如果有错误感谢请大家批评指出&#xff0c;及时修改感谢大家点赞&#x1f44d;收藏⭐评论✍ Qt常用控件 | 布局管理器 | 网格布局Grid Layout 文章编号&#xff1a…

成品短视频APP源码搭建

在数字化时代&#xff0c;短视频已成为全球范围内的流行趋势&#xff0c;吸引了大量的用户和内容创作者。对于有志于进入短视频领域的企业和个人来说&#xff0c;成品短视频APP源码搭建提供了一条快速、高效的路径。本文将探讨成品短视频APP源码搭建的过程及其优势&#xff0c;…

Mac维护神器CleanMyMac X成为你的苹果电脑得力助手

在数字化时代&#xff0c;Mac电脑已成为众多用户的首选。然而&#xff0c;随着频繁的使用和数据量的日益增长&#xff0c;许多Mac用户面临着系统杂乱、存储空间不足以及隐私保护等问题。幸运的是&#xff0c;"CleanMyMac X"这款优化和清理工具应运而生&#xff0c;它…