并发编程(一)线程基础知识与线程控制

进程与线程

进程:如任务管理器中各种程序叫做正在运行的进程。对于操作系统来说,仅仅是一个数据结构,并不真实的执行代码

线程:真实执行代码的

每个进程启动的是时候会同步启动一个主线程即main函数,当main函数结束时,该线程结束并销毁,同时其他线程随之销毁

线程都有一个需要执行的代码块称为线程回调函数

真并发与伪并发

真并发

当cpu是双核或者多核时,并不会一核心一任务,而是由单核心切换转为多核心切换,此时也称作真并发

伪并发

在早期的cpu即单核cpu中,因性能核心各方面较为落后,并发编程实际是一个伪并发编程,即系统中所有进程按照优先级去抢占cpu时间片,也就是系统一会执行这个一会执行哪个。

由于抢占时间片所需时间较短,所以我们并不觉得程序卡顿。但各进程抢占cup时间片是一个很麻烦的事情,cpu虽然提供任务切换的功能即TSS任务段,但Windows并不使用。

因为Windows实现了线程调度,即再线程切换时,上个线程代码执行到的地方的线程的状态,线程上下文,通用寄存器,段寄存器,硬件调试寄存器,EIP(指令指针寄存器),EFLAGS等都会被Windows通过Windows(Context)保存,直到再次切换回来后再加载

并发形式

  1. 多进程并发:一个可执行程序里只有一个线程,同时启动多个进程执行,如浏览器
  2. 多线程并发:一个进程内运行多个线程,变量的访问

如:

Value = 100 全局变量

A B A,B两个线程

A,B线程访问Value,访问值都是100

现AB两线程都对Value进行++

操作完成后,Value的值为101,这种情况叫做线程同步问题(后续有讲解)

线程的生存周期

回调函数执行完毕,自然死亡

主线程死亡,被动死亡

并发函数分类实践

如下是一个简单的并发程序描述:

#include <iostream>

#include <thread> 线程库

普通函数

void FirstThreadCallBack() 构建一个新的函数

{

    for (size_t i = 0; i < 100000; i++)

    {

       std::cout << "First:" << i << std::endl;

    }

}

int main()

{

    std::thread obj(FirstThreadCallBack); 声明线程对象,并在其构造函数中传入要并发的函数地址(也可是类等等其他东西)。在此开始启动一个线程去执行线程回调函数

    for (size_t i = 0; i < 100000; i++)

    {

       std::cout << "main:"<< i << std::endl;

    }

System(“pause”); 程序暂停至此,不会死亡

return 0;

}

此时程序会同时进行上述两个函数

仿函数

class Exec  一个类的仿函数

{

public:

    void operator()()const

    {

       std::cout << "Exec" << std::endl;

    }

};

int main()

{

    Exec e;

    std::thread obj(e);

System(“pause”); 程序暂停至此,不会死亡

return 0;

}

打印Exec

Lambda 

int main()

{

    std::thread obj([] {std::cout << "Lambda" << std::endl; });

System(“pause”); 程序暂停至此,不会死亡

return 0;

}

打印Lambda

综上可知,任何可以调用的类型都可以用于线程对象的构造函数传参

线程死亡

一旦线程启动了,我们就需要知道线程是怎么死的

1.自然死亡 thread析构函数terminate(),主函数执行完毕时,析构函数执行

   非自然死亡 thread析构函数执行完毕时,并发的函数即thread传参函数不一定执行完毕

2.等待 绝对的自然死亡 等待函数执行完毕后,程序再往下走

3.不再等待(主线程存活时后台运行)依赖于主线程的存活

4.如果一个线程是Windows原生线程,主线程销毁后其也会死亡

如下我们验证Windows原生线程的死亡:

包含头文件Windows.h

创建一个原生线程需要调用CreateThread()API

利用CreateThread()API中的一个:

DWORD ThreadCallBack(LPVOID lpThreadParameter)

{

    for (size_t i = 0; i < 100000; i++)

    {

        std::cout << "First:" << i << std::endl;

    }

    return 0;

}

int main()

{

    CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)ThreadCallBack, NULL, NULL, NULL);API函数,创建了一个原生线程

    return 0;

}

此时运行程序,发现随着主线程的结束该原生线程死亡

等待

以下讲述等待作用:

1.原生线程等待死亡

int main()

{

    HANDLE hThread = CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)ThreadCallBack, NULL, NULL, NULL);

 此处是拿个该原生线程的句柄即控制该线程的启动器

    WaitForSingleObject(hThread, -1); -1代表永久等待

    return 0;

}

此时发现运行程序原生线程不会死亡,直到它运行完毕

2.C++并发编程等待死亡:

int main()

{

    std::thread obj(FirstThreadCallBack);

    obj.join(); 阻塞等待,作用是在此处等待函数的返回

    return 0;

}

此时运行程序,不会报错也不会死亡

不再等待

int main()

{

    std::thread obj(FirstThreadCallBack);

    obj.detach(); 不再等待:当其所在命名空间结束时,直接死亡

    for (size_t i = 0; i < 100000; i++)

    {

        std::cout << "main:" << i << std::endl;

    }

如在此处加一个循环,程序在执行该循环时,程序没有死亡,并发函数也不会死亡,而是一起执行两个函数

    return 0;

}

并发特殊情况

情况一

原本在后台运行的线程,由于各种问题,线程提前崩坏,没有正常返回,等待函数没有接收到返回,抛一个异常,遇到此情况跳过即可

情况二

并发线程不仅可以传函数地址,也可以传其他多个参数,如下:

包含头文件:string.h

void Print(std::string szBuffer,int nCount)

{

    for (size_t i = 0; i < nCount; i++)

    {

        std::cout << szBuffer << ":" << i << std::endl;

    }

}

int main()

{

    std::thread obj(Print,"rkvir",50);

    system(“pause”);

    return 0;

}

程序运行,出现一个新现象

在循环执行时,出现

原因:先打印rkvir,然后切片回来,执行system(“pause”),再切片回来打印38

这个现象很形象展示了线程同步问题(后续讲解)

  

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

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

相关文章

智慧公厕:引领城市卫生管理新时代

在智慧城市建设中&#xff0c;智慧公厕作为城市环境卫生信息化的重要组成部分&#xff0c;扮演着关键角色。它不仅可以提升城市管理水平&#xff0c;满足人民群众的需求&#xff0c;还能提高公厕使用体验和城市环境卫生水平。如广州中期科技有限公司自主研发的智慧公厕管理系统…

第10章 通信业务

文章目录 10.1.1 通信行业1、通信行业的界定2、通信行业的特点 10.1.2 通信企业10.1.3 通信终端1、通信终端的分类2、终端发展趋势 10.2.1 通信业务的定义及分类10.2.2 基础电信业务1、第一类基础电信业务A11 固定通信业务A12 蜂窝移动通信业务A13 第一类卫星通信业务A14 第一类…

代码随想录 Leetcode1. 两数之和

题目&#xff1a; 代码&#xff08;首刷看解析 2024年1月15日&#xff09;&#xff1a; class Solution { public:vector<int> twoSum(vector<int>& nums, int target) {int another 0;unordered_map<int,int> hash;for(int i 0; i < nums.size();…

为什么有人说PMP是水证,它的含金量到底怎么样?

在我国大陆&#xff0c;有好多证书被商业化得太重了&#xff0c;甚至演变成了个人或一些公司摇钱的工具。所以有些证书受人吹捧它崛起的快&#xff0c;但是活不长&#xff0c;甚至“夭折”&#xff0c;比如以前微软系列的证书&#xff1b; 而PMP认证从国外引进大陆这么多年了&…

NLP(十八):LLM 的推理优化技术纵览

原文&#xff1a;NLP&#xff08;十八&#xff09;&#xff1a;LLM 的推理优化技术纵览 - 知乎 目录 收起 一、子图融合&#xff08;subgraph fusion&#xff09; 1.1 FasterTransformer by NVIDIA 1.2 DeepSpeed Inference by Microsoft 1.3 MLC LLM by TVM 二、模型压…

Grind75第10天 | 133.克隆图、994.腐烂的橘子、79.单词搜索

133.克隆图 题目链接&#xff1a;https://leetcode.com/problems/clone-graph 解法&#xff1a; 这个题是对无向图的遍历&#xff0c;可以用深度优先搜索和广度有限搜索。 下面这个图比较清楚的说明了两种方法的区别。 DFS&#xff1a;从A开始克隆&#xff0c;遍历两个邻居…

数据结构期末复习(C语言版)

一、绪论 1.数据结构的术语 数据&#xff1a;所有能输入计算机并被计算机程序处理的符号的总称&#xff1b;数据元素&#xff1a;数据的基本单位&#xff1b;数据项&#xff1a;组成数据元素的、有独立含义的、不可分割的最小单位&#xff1b;数据对象&#xff1a;是性质相同…

springboot基于WEB的旅游推荐系统设计与实现

&#x1f345;点赞收藏关注 → 私信领取本源代码、数据库&#x1f345; 本人在Java毕业设计领域有多年的经验&#xff0c;陆续会更新更多优质的Java实战项目希望你能有所收获&#xff0c;少走一些弯路。&#x1f345;关注我不迷路&#x1f345;一 、设计说明 1.1选题动因 当前…

云原生微服务之分布式锁框架 Redisson

&#x1f339;作者主页&#xff1a;青花锁 &#x1f339;简介&#xff1a;Java领域优质创作者&#x1f3c6;、Java微服务架构公号作者&#x1f604; &#x1f339;简历模板、学习资料、面试题库、技术互助 &#x1f339;文末获取联系方式 &#x1f4dd; 系列专栏目录 [Java项目…

阿里云国际服务器设置安全防护程序

阿里云云服务器&#xff08;ECS&#xff09;提供弹性、安全、高性能、高性价比的虚拟云服务器&#xff0c;满足您的所有需求。立即在这里免费注册&#xff01; 常见 Web 应用程序 请勿对 Web 服务控制台&#xff08;如 WDCP、TOMCAT、Apache、Nginx、Jekins、PHPMyAdmin、Web…

陪诊小程序开发|陪诊软件定制|陪诊系统成品功能包含哪些?

陪诊小程序是一种便捷的工具&#xff0c;为用户提供一系列服务和功能&#xff0c;方便患者在就医过程中获得更好的体验和效果。接下来我们将介绍几个主要的陪诊小程序功能。 陪诊小程序开发功能&#xff1a; 一、预约挂号功能。陪诊小程序能够连接用户和医疗机构的系统&#x…

从头安装与使用一个docker GPU环境

GPU版docker的安装与使用 欢迎使用GPU版docker安装使用说明使用官方教程安装docker新建一个GPU版docker环境调用docker环境执行本地python文件 欢迎使用GPU版docker安装使用说明 使用官方教程安装docker 导入源仓库的GPG key curl -fsSL https://download.docker.com/linux/…

虹科分享 | 用Redis为LangChain定制AI代理——OpenGPTs

文章速览&#xff1a; OpenGPTs简介Redis在OpenGPTs中的作用在本地使用OpenGPTs在云端使用OpenGPTsRedis与LangChain赋能创新 OpenAI最近推出了OpenAI GPTs——一个构建定制化AI代理的无代码“应用商店”&#xff0c;随后LangChain开发了类似的开源工具OpenGPTs。OpenGPTs是一…

05-微服务Sentinel流量哨兵

一、Sentinel介绍 1.1 什么是Sentinel 分布式系统的流量防卫兵&#xff1a;随着微服务的普及&#xff0c;服务调用的稳定性变得越来越重要。Sentinel以“流量”为切入点&#xff0c;在流量控制、断路、负载保护等多个领域开展工作&#xff0c;保障服务可靠性。特点&#xff1…

VSCode搭建 .netcore 开发环境

一、MacOS 笔者笔记本电脑上安装的是macOS High Sierra(10.13)&#xff0c;想要尝试一下新版本的.netcore&#xff0c;之前系统是10.12时&#xff0c;.netcore 3.1刚出来时安装过3.1版本&#xff0c;很久没更新了&#xff0c;最近.net8出来了&#xff0c;想试一下&#xff0c;…

redis夯实之路-键过期与发布订阅详解

设置键的生存时间或过期时间 Setex&#xff08;单位s&#xff09;&#xff0c;expire&#xff08;s&#xff09;&#xff0c;pexpire&#xff08;ms&#xff09;可以设置键的生存时间&#xff0c; Expirate&#xff0c;pexpirate设置键的过期时间&#xff08;timestamp的时间…

day08

回顾 1.选择排序原理: 找到最小值的下标&#xff0c;交换 2.冒泡排序原理: 比较相邻的两个元素&#xff0c;把最小值放到左边。第一次比较的时候最大值放到最右边了&#xff0c;以此类推今天的内容 1类和对象 2.类和对象内存 3.构造方法 1.从生活的角度区理解面向对象开发 有两…

Hologres + Flink 流式湖仓建设

Hologres Flink 流式湖仓建设 1 Flink Hologres2 实时维表 Lookup 1 Flink Hologres holo在实时数仓领域非常受欢迎&#xff0c;一般搭配flinkhologres来做实时数仓&#xff0c;中间分层用holo&#xff0c;上下游一般依赖于holo的binlog来下发数据 2 实时维表 Lookup Holo…

展厅设计原则都包含哪些

1、风格与品牌一致性 展厅设计应体现企业的品牌形象和价值观&#xff0c;从色彩、材料选择到整体布局&#xff0c;都应与企业的品牌风格保持一致。 2、空间规划和流线设计 展厅内不同区域需要有合理的空间规划和流线设计&#xff0c;使参观者能够便利地浏览展品和了解企业信息。…

基于YOLOv8深度学习的苹果叶片病害智能诊断系统【python源码+Pyqt5界面+数据集+训练代码】深度学习实战

《博主简介》 小伙伴们好&#xff0c;我是阿旭。专注于人工智能、AIGC、python、计算机视觉相关分享研究。 ✌更多学习资源&#xff0c;可关注公-仲-hao:【阿旭算法与机器学习】&#xff0c;共同学习交流~ &#x1f44d;感谢小伙伴们点赞、关注&#xff01; 《------往期经典推…