当前位置: 首页 > news >正文

C++学习之线程详解

多线程是开发中必不可少的,往往我们需要多个任务并行,就需要多线程开发;就好比图像检测和图像结果的处理,这就是一个可闭环的任务,用多线程是可以加速这个任务的;

线程的状态

就绪态:线程能够运行,正在等待处理机资源;

运行态:正在运行,可能有多个线程处于运行态;

阻塞态:线程由于等待某些条件而无法运行,例如IO、锁、互斥量等;

终止态:线程从起始函数返回或被取消;

多线程的构建

有三种方式可以构建多线程,前提是都需要引入pthread.h这个头文件;

1、函数;

2、仿函数;

3、Lambda表达式;

三者的本质都是在调用函数;

1

2

3

4

5

6

7

8

9

10

11

// 函数方式

voidfun(string s){

cout<< &s<<endl;

cout<<"first thread programm"<<s<<endl;

}

intmain(){

string s ="Hell world";

threadth =thread(fun, s);

th.join();

}

上面代码为最简单线程的一个构造;

join函数是一个等待线程完成函数,主线程需要等待子线程运行结束才可以结束;还有一个detach的函数,会让线程在后台运行,需要等到程序退出才结束;

计算时间

计算时间在这里介绍两种方式:

一、程序运行时间

1

2

3

4

5

6

7

8

longn =0;

clock_tstart,finish;

start=clock();

while(n<1000000000)

n++;

finish=clock();

printf("spend time %f s \n", (double)(finish-start)/CLOCKS_PER_SEC);

printf("spend time %f ms \n", (double)(finish-start)/1000);

这种方式和系统时间无关,一般用来调试时打印时间;

二、chrono

1

2

3

4

5

6

7

8

9

10

11

12

#include <chrono>

//方式三 chrono

std::chrono::system_clock::time_point Cstart = std::chrono::system_clock::now();//系统时间

// std::chrono::steady_clock::time_point Cstart = std::chrono::steady_clock::now(); //稳定时间

longn =0 ;

while(n<1000000000)n++;

std::chrono::system_clock::time_point Cend = std::chrono::system_clock::now();//系统时间

std::chrono::duration<float> spend_time = Cend-Cstart;

cout<<spend_time.count()<<endl;

这个方式用系统时间进行计算,在实际程序中用这个方式;

共享资源和互斥锁

关于互斥锁的概念,引用这篇博主的讲解:文章

引入互斥锁原因:当有两个线程共享一块资源时,容易造成冲突,也就是上个线程还没结束就进行下个线程,举个例子就是读写操作,添加互斥锁可以很好的解决这个冲突问题;

互斥锁是个简单的加锁方法,互斥锁只有两种状态:上锁(lock)和解锁(unlock);

互斥锁特点:

1、原子性:把一个互斥量锁定为一个原子操作,这意味着如果一个线程锁定了一个互斥量,没有其他线程在同一时间可以成功锁定这个互斥量;

2、唯一性:如果一个线程锁定了一个互斥量,在它解除锁定之前,没有其他线程可以锁定这个互斥量;

3、非繁忙等待:如果一个线程已经锁定了一个互斥量,第二个线程又试图去锁定这个互斥量,则第二个线程将被挂起(不占用任何cpu资源),直到第一个线程解除对这个互斥量的锁定为止,第二个线程则被唤醒并继续执行,同时锁定这个互斥量。

互斥锁的使用:

1

2

3

4

5

mutex mtx;//创建互斥锁对象

mtx.lock();

g_pcm_elapseds.push_back(std::make_pair(pcm_data, elapsed));// 执行语句

mtx.unlock();

condition_variable

condition_variable条件变量可以阻塞(wait)调用的线程直到使用(notify_one或notify_all)通知恢复为止

使用案例:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

std::mutex mtx;

std::condition_variable cv;

boolready =false;

voidprint_thread_id(intid){

std::unique_lock<std::mutex> lck(mtx);

cv.wait(lck,[]{returnready;});

std::cout<<"thread"<<id <<endl;

}

voidgo(){

std::unique_lock<std::mutex> lck(mtx);

ready =true;

cv.notify_all();// 唤醒所有线程

};

intmain(){

std::threadthreads[10];

for(inti=0;i<10;i++){

threads[i] = std::thread(print_thread_id,i);

}

std::cout<<" thread read all done"<<endl;

go();

for(auto &th:threads) th.join();

return0;

}

线程池

作用:每一个任务都起一个线程,这样的效率是不高的,起一个线程池,哪个线程空闲就来处理任务,这样的结构高效;

http://www.jsqmd.com/news/873147/

相关文章:

  • 联发科MT6833与MT6853 5G核心板:规格对比与产品选型实战指南
  • 西恩士液冷板清洁度检测设备/检测仪/分析系统,全链路一站式解决 - 工业设备研究社
  • CM1-DAY1题目总结
  • STM32H5安全连接AWS IoT:基于TrustZone与Secure Manager的物联网方案
  • C/C++中#define与typedef的本质区别:从编译原理到工程实践
  • AI Agent如何重构课堂?揭秘2024年全球87所试点校的3个颠覆性教学范式
  • Purple Pi OH开发板7天实战OpenHarmony:从环境搭建到应用开发
  • 2026年使用降AI工具合法性深度解读:降AI到底是不是学术不端免费完整解析
  • JS逆向实战:破解前端加密参数payload与sig的完整流程
  • C++引用的详细解释
  • Linux终端字体终极指南:10款精选字体与安装优化全解析
  • 【流体】二维稳态不可压缩层流通道流利用FVM和SIMPLE 解平行板间层流的速度、压力和温度【含Matlab源码 15558期】
  • 为开源项目OpenClaw配置Taotoken作为AI能力供应商的步骤
  • RK3568 SPI驱动实战:MCP2515 CAN控制器寄存器读写原理与优化
  • 18分钟攻破GitHub:TeamPCP供应链攻击全技术解析与防御新范式
  • 如何快速解决Windows 11区域模拟问题:完整API钩子技术指南
  • 为OpenClaw智能体工作流配置Taotoken后端模型
  • S-Video端口ESD防护方案:TVS阵列选型与PCB布局实战指南
  • 芯片设计后期DFT友好ECO:原理、实践与工具选型
  • 全志T113-S3开发板XR829 WiFi蓝牙驱动加载、固件配置与稳定性测试全攻略
  • 西恩士液冷板清洁度萃取设备/清洗机:从源头守护液冷系统“血液”洁净 - 工业设备研究社
  • CVE-2026-9082深度解析:Drupal十年最致命SQL注入,补丁发布3小时即遭全球轰炸
  • 基于RK3399核心板的智能PCR仪开发:从嵌入式系统到高精度温控
  • 为内部培训系统集成Taotoken提供个性化学习内容生成与答疑
  • Photoshop 2026(PSv27.x)详细安装教程与下载地址
  • 【学习笔记】探讨大模型应用安全建设系列8——成果汇报与持续运营
  • 为什么92%的健身APP AI聊天功能被弃用?(行为日志分析+3周A/B测试结论)
  • RK3588蓝牙功能完整测试指南:从驱动到应用实战
  • 嵌入式开发硬件生态构建:MIPI屏、UVC摄像头与4G模块的选型与集成实战
  • S-Video端口ESD防护方案解析:低电容TVS阵列选型与PCB布局实战