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

进程与线程

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

线程:真实执行代码的

每个进程启动的是时候会同步启动一个主线程即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

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

  

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

倒F天线设计经验分享

一、IFA天线理论分析 为了改善&#xff29;&#xff2c;&#xff21;天线难以使用的缺点&#xff0c;在&#xff29;&#xff2c;&#xff21;天线的基础上再增加一个倒L结构&#xff0c;形成IFA天线&#xff0c;此种天线体积小、易于匹配并具有双极化的特点&#xff0c;而在蓝…

帆软报表11.0.19增加postgres数据源方案

项目使用postgres数据库&#xff0c;帆软报表集成开发时需要手工增加该数据源。 https://help.fanruan.com/finereport/doc-view-2563.html 但增加数据源后测试报告无此驱动&#xff0c;经查看文档&#xff0c;现在是通过驱动管理来上传&#xff0c; 但新版又不允许上传驱动JAR…

外贸群发邮件最好的软件?群发软件哪个好?

外贸开发信群发软件推荐&#xff1f;做外贸用什么邮件群发软件&#xff1f; 在外贸业务中&#xff0c;与潜在客户建立联系并保持沟通是至关重要的。那么&#xff0c;如何快速有效地发送邮件给大量的潜在客户呢&#xff1f;这就涉及到了外贸群发邮件。蜂邮EDM来探讨一下&#x…

presto/trino 入门介绍实战

引言 Presto是一款分布式SQL查询引擎&#xff0c;它能够在大规模数据集上实现快速、交互式的查询。本文将介绍Presto的基本概念并结合一些实际的代码示例&#xff0c;能够让的大家快速入门并在实际项目中应用。 官网&#xff1a;Launch Presto: Local download, JDBC, Docker…

11.云原生分布式数据库之TIDB

云原生专栏大纲 文章目录 为什么使用TIDB后端视角运维视角基础架构视角 TiDB Operator 简介软件版本要求部署tidbTIDB工具helm常用命令TIDB学习推荐资料 为什么使用TIDB 从后端视角、运维视角和基础架构视角来看&#xff0c;使用 TiDB 作为数据库系统可以获得分布式架构、高可…

目标检测应用场景—数据集【NO.25】牛行为检测数据集

写在前面&#xff1a;数据集对应应用场景&#xff0c;不同的应用场景有不同的检测难点以及对应改进方法&#xff0c;本系列整理汇总领域内的数据集&#xff0c;方便大家下载数据集&#xff0c;若无法下载可关注后私信领取。关注免费领取整理好的数据集资料&#xff01;今天分享…

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

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

动物多指标生理监测:ZL-019A大小鼠饮食饮水监测系统

ZL-019A大小鼠饮食饮水监测系统是一款能够实时监测和分析动物的饮食、饮水、站立、活动量和活动轨迹等行为和代谢过程的智能系统。 本系统旨在定期测量实验动物的饮食饮水摄入行为&#xff0c;用户可根据需要自定义测量时间。通过定期测量&#xff0c;研究者无需再费心记录单个…

代码随想录 Leetcode454. 四数相加 II

题目&#xff1a; 代码 (首刷看解析 2024年1月15日&#xff09;&#xff1a; class Solution { public:int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) {int n nums1.size();u…

【干货】数字化工厂常见术语合集

本文将为大家介绍一些行业通俗名称&#xff0c;希望对于从事“数字工厂”行业的朋友以及正在求职的朋友们有所助益。 数字化工厂&#xff08;"Digital factory"&#xff0c;简写为"DF"&#xff09;&#xff1a;是指利用先进的信息技术和数字化解决方案&am…

关于如何禁用、暂停或退出OneDrive等操作,看这篇文件就够了

​想知道如何禁用OneDrive?你可以暂停OneDrive的文件同步,退出应用程序,阻止它在启动时打开,或者永远从你的机器上删除该应用程序。我们将向你展示如何在Windows计算机上完成所有这些操作。 如何在Windows上关闭OneDrive 有多种方法可以防止OneDrive在你的电脑上妨碍你。…

AI自动写文章的软件有哪些?分享五款实用的

据相关数据统计&#xff0c;AI自动写文章的软件逐渐成为了现实。这些写作软件利用强大的自然语言处理和机器学习算法&#xff0c;能够自动生成文章&#xff0c;为写作工作提供了极大的便利。在本文中&#xff0c;我将向大家介绍五款实用的AI自动写文章的软件&#xff0c;一起来…

打破效率瓶颈:运用Excel提升文秘与行政工作质量

文章目录 一、数据整理二、数据分析三、报表制作四、图表展示五、模板应用六、宏编程七、安全与隐私《Excel高效办公&#xff1a;文秘与行政办公&#xff08;AI版&#xff09;》编辑推荐内容简介作者简介目录获取方式 在现代企业中&#xff0c;文秘与行政办公人员的工作内容繁杂…

文件批量重命名:如何给文件自定义名称,大量文件重命名的方法

在日常生活和工作中&#xff0c;经常要处理大量的文件&#xff0c;例如把文件重命名。手动重命名每个文件不仅耗时&#xff0c;而且容易出错。现在一起来看云炫文件管理器如何按自定义名称批量给文件重命名的技巧。 文件名自定义名称前后缩略图对比。 用自定义名称批量重命名…

Unity 编辑器篇|(五)编辑器拓展GUILayout类 (全面总结 | 建议收藏)

目录 1. 前言2. 参数3. 功能3.1 按钮&#xff1a;Button、RepeatButton3.2 文本&#xff1a;Label、TextArea、TextField、PasswordField3.3 工具栏&#xff1a;Toolbar3.4 切换框&#xff1a;Toggle3.5 滚动条&#xff1a;HorizontalScroll 、VerticalScroll3.6 滑条&#xff…

优思学院|质量管理五大工具和七大手法要点总结|2024

在现代企业管理中&#xff0c;质量管理是核心竞争力的重要组成部分。它不仅关系到产品的品质&#xff0c;更直接影响到企业的市场信誉和经济效益。本文将深入探讨质量管理中的五大工具及七大手法&#xff0c;这些工具和手法都贯穿了六西格玛DMAIC五步的方法论之中&#xff0c;是…

MYSQL第三次作业--单表查询

第三次作业 一、创建worker表 mysql> create table worker(-> 部门号 int(11) not null,-> 职工号 int(11) not null,-> 工作时间 date not null,-> 工资 float(8,2) not null,-> 政治面貌 varchar(10) not null default群众,-> 姓名 varchar(20) not n…

arrow,一个神奇的 Python 库!

更多资料获取 &#x1f4da; 个人网站&#xff1a;ipengtao.com 大家好&#xff0c;今天为大家分享一个神奇的 Python 库 - arrow。 Github地址&#xff1a;https://github.com/arrow-py/arrow 日期和时间处理是许多应用程序中的常见任务&#xff0c;但在 Python 中&#xf…

聚类算法之Kmeans聚类详解

聚类算法是无监督学习算法&#xff0c;它根据样本之间的相似性&#xff0c;将样本划分到不同的类别中&#xff1b;不同的相似度计算方法&#xff0c;会得到不同的聚类结果&#xff0c;常用的相似度计算方法有欧氏距离法。聚类算法的目的是在没有先验知识的情况下&#xff0c;自…

亚马逊卖家必备神器:鲲鹏系统助力产品排名飙升

亚马逊鲲鹏系统是一款功能强大的工具&#xff0c;为亚马逊卖家提供了多种实用功能&#xff0c;旨在提高产品排名、增加自然流量&#xff0c;并模拟真实的人类操作&#xff0c;以规避亚马逊的检测系统。 下面是亚马逊鲲鹏系统的主要功能和8大特点&#xff1a; 主要功能&#xf…