WIN32核心编程 - 线程操作(三) 线程优先级 - 生产者与消费者模式

  • 公开视频 -> 链接点击跳转公开课程
  • 博客首页 -> 链接点击跳转博客主页

目录

线程优先级和调度

生产者与消费者模式

关键概念

实现细节

案例描述(一对一)

案例描述(多对一)


线程优先级和调度

  • 在Windows操作系统中,线程优先级与进程优先级共同决定了线程的最终优先级。
  • 进程优先级类决定了进程内所有线程的基本优先级,并且每个线程可以在此基础上有自己的优先级设置。

  • Windows提供了几个不同的进程优先级类:

    • IDLE_PRIORITY_CLASS

    • BELOW_NORMAL_PRIORITY_CLASS

    • NORMAL_PRIORITY_CLASS

    • ABOVE_NORMAL_PRIORITY_CLASS

    • HIGH_PRIORITY_CLASS

    • REALTIME_PRIORITY_CLASS

  • 在每个进程优先级类内,线程可以有以下优先级:

    • THREAD_PRIORITY_LOWEST

    • THREAD_PRIORITY_BELOW_NORMAL

    • THREAD_PRIORITY_NORMAL

    • THREAD_PRIORITY_ABOVE_NORMAL

    • THREAD_PRIORITY_HIGHEST

    • THREAD_PRIORITY_TIME_CRITICAL

  • 线程调度与时间碎片

    • Windows使用抢占式调度来分配CPU时间给线程。每个线程都会被分配一个时间片,它是线程可以在被挂起之前连续运行的时间量。

    • Windows中的实时优先级类别允许线程以最小的延迟执行。这些线程几乎总是优先于其他线程运行,除非有其他更高优先级的实时线程。这对于需要精确计时或快速响应的任务至关重要。

#include <iostream>
#include <Windows.h>DWORD WINAPI WorkThread(LPVOID lp)
{	std::cout << GetThreadPriority(GetCurrentThread());return 0;
}int main()
{// 设置进程优先级SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS);// 获取进程优先级GetPriorityClass(GetCurrentProcess());// 创建执行线程HANDLE hThread = CreateThread(NULL, 0, WorkThread, NULL, 0, NULL);SetThreadPriority(hThread, THREAD_PRIORITY_HIGHEST);WaitForSingleObject(hThread, INFINITE);return 0;
}

生产者与消费者模式

关键概念

  1. 生产者(Producer) - 负责生成数据并将其放入缓冲区的线程或进程。通常会在没有足够空间放入新数据时等待。

  2. 消费者(Consumer) - 负责从缓冲区取出数据并处理它的线程或进程。如果缓冲区为空,消费者将等待直到有数据可用。

  3. 缓冲区(Buffer) - 一个有限的存储空间,用于生产者存放数据,消费者从中取出数据。它可以是一个队列、数组或任何其他形式的集合。

  4. 同步机制 - 生产者和消费者需要通过某种方式来协调它们的工作,以确保它们不会在同一时间内对缓冲区进行写入或读取操作。常见的同步机制包括互斥锁(mutexes)、信号量(semaphores)和条件变量(condition variables)。

实现细节

  1. 互斥锁 - 确保在任意时刻只有一个线程可以访问缓冲区。这防止了并发访问导致的数据竞争条件。

  2. 信号量 - 可以用来表示缓冲区中可用资源的数量。通常有两个信号量:一个表示空位的数量(对生产者而言),另一个表示数据项的数量(对消费者而言)。

案例描述(一对一)

  • 假设有一个工厂(生产者)和一个零售商店(消费者)。工厂生产产品并将其放入仓库(缓冲区),而零售商店从仓库中取出产品并卖给客户。仓库的空间是有限的,所以当它满了时,工厂必须停止生产,等待零售商店取走一些产品。同样,如果仓库是空的,零售商店必须等待工厂生产新的产品。
  1. 初始化:设置一个有限大小的缓冲区以及必要的同步机制。

  2. 生产者线程执行以下操作:

    • 确认缓冲区中是否有空间可用。

    • 如果缓冲区已满,则等待直到有空位。

    • 生产一个数据项并将其放入缓冲区中。

    • 通知消费者缓冲区中有新的数据项可用。

  3. 消费者线程执行以下操作:

    • 确认缓冲区内是否有数据项。

    • 如果缓冲区为空,则等待直到有数据项。

    • 从缓冲区中取出一个数据项进行处理。

    • 通知生产者已从缓冲区中取出数据项,使其可以添加新的数据项。

  4. 同步机制:

    • 使用互斥锁(mutex)保护对缓冲区的访问,以保证任一时刻只有一个线程可以操作缓冲区。

    • 使用条件变量(condition variable)使线程在特定条件不满足时等待,并在条件满足时接到通知以继续执行。

  5. 终止过程:

    • 生产者在完成既定数量的生产后终止。

    • 消费者在消费完所有生产者生产的产品后终止。

#include <iostream>
#include <Windows.h>// 缓冲容量
#define BUFFER_SIZE 5
int Buffer[BUFFER_SIZE] = { 0 };// 交接信息
int In = 0;
int Out = 0;
int Sum = 0;
int Count = 0;// 同步对象
HANDLE hMutex = NULL;
HANDLE hProduce = NULL;
HANDLE hConsume = NULL;// 生产者
DWORD WINAPI Produce(LPVOID lp)
{for (size_t i = 0; i < Sum; i++){// 等待是否可以生成的信号WaitForSingleObject(hProduce, INFINITE);// 获取互斥体所有权WaitForSingleObject(hMutex, INFINITE);// 生成商品放入仓库Buffer[In] = i;In = (In + 1) % BUFFER_SIZE;++Count;std::cout << "Produce -> " << i << std::endl;// 释放互斥体所有权ReleaseMutex(hMutex);if (Count == 1){SetEvent(hConsume);}else if (Count < BUFFER_SIZE){SetEvent(hProduce);}else{ResetEvent(hProduce);}Sleep(rand() % 100);}return 0;
}// 消费者
DWORD WINAPI Consume(LPVOID lp)
{int nConut = 1;while (1){// 等待是否可以消费的信号WaitForSingleObject(hConsume, INFINITE);// 获取互斥体所有权WaitForSingleObject(hMutex, INFINITE);// 消费商品取出仓库int Data = Buffer[Out];Out = (Out + 1) % BUFFER_SIZE;--Count;std::cout << "Consume -> " << Data << std::endl;// 释放互斥体所有权ReleaseMutex(hMutex);if (Count == BUFFER_SIZE - 1){SetEvent(hProduce);}if (Count > 0){SetEvent(hConsume);}else{ResetEvent(hConsume);}Sleep(rand() % 100);// 条件满足 结束线程if (nConut == Sum) break;}return 0;
}int main()
{Sum = 20;// 初始同步对象hMutex = CreateMutex(NULL, FALSE, NULL);hProduce = CreateEvent(NULL, TRUE, TRUE, NULL);hConsume = CreateEvent(NULL, TRUE, FALSE, NULL);// 生产消费线程HANDLE thProduce = CreateThread(NULL, 0, Produce, NULL, 0, NULL);HANDLE thConsume = CreateThread(NULL, 0, Consume, NULL, 0, NULL);// 等待线程完成WaitForSingleObject(thProduce, INFINITE);WaitForSingleObject(thConsume, INFINITE);// 关闭对象句柄CloseHandle(hMutex);CloseHandle(hProduce);CloseHandle(hConsume);CloseHandle(thProduce);CloseHandle(thConsume);return 0;
}

案例描述(多对一)

  • 假设有一个工厂,拥有多条生产线(生产者线程),每条生产线负责生产不同类型的产品。这些产品随后会被送往一个共享的仓库(缓冲区),以便单个零售商(消费者线程)从中取走产品并销售。由于仓库的容量有限,当仓库满时,所有生产线必须暂停生产,直到仓库中有足够的空间再继续生产。同样地,如果仓库为空,零售商也必须等待,直到仓库中有产品可供取出。
  • 关键步骤

  • 初始化:设置一个有限大小的缓冲区以及必要的互斥锁和条件变量(或事件)。

  • 生产者线程执行以下操作:

    1. 确认缓冲区中是否有空间可用。

    2. 如果缓冲区已满,则等待直到有空位(通过条件变量或事件)。

    3. 获取互斥锁,生产一个数据项并将其放入缓冲区中,然后释放互斥锁。

    4. 通知消费者缓冲区中有新的数据项可用。

  • 消费者线程执行以下操作:

    1. 确认缓冲区内是否有数据项。

    2. 如果缓冲区为空,则等待直到有数据项(通过条件变量或事件)。

    3. 获取互斥锁,从缓冲区中取出一个数据项进行处理,然后释放互斥锁。

    4. 通知生产者已从缓冲区中取出数据项,使其可以添加新的数据项。

  • 实现注意事项

    • 死锁避免:确保获取和释放锁的顺序一致,避免出现死锁情况。

    • 条件竞争处理:使用互斥锁保护所有访问共享资源(例如,缓冲区和计数器)的操作,确保每次只有一个线程可以执行这些操作。

    • 适当的信号通知:在修改了可能影响其他线程行为的共享状态后(例如,添加或移除缓冲区中的数据项),及时通过条件变量或事件发送适当的信号,以唤醒等待的线程。

#include <iostream>
#include <queue>
#include <Windows.h>// 共享数据
HANDLE hThreads[3] = { NULL };
std::queue<int> Queue;
CONST int Max = 10;// 线程竞态
CRITICAL_SECTION QueueLock = { 0 };
HANDLE hQueueNotEmpty = NULL;
HANDLE hQueueNotFull = NULL;
BOOL bProduceFinished = FALSE;// 生产者线程
DWORD WINAPI Produce(LPVOID lp)
{for (size_t i = 0; i < 50; i++){WaitForSingleObject(hQueueNotFull, INFINITE);EnterCriticalSection(&QueueLock);if (Queue.size() >= Max){ResetEvent(hQueueNotFull);}else{Queue.push(i);std::cout << "ID -> " << GetCurrentThreadId() << " Produce -> " << i << std::endl;SetEvent(hQueueNotEmpty);}LeaveCriticalSection(&QueueLock);Sleep(rand() % 100);}EnterCriticalSection(&QueueLock);bProduceFinished = TRUE;LeaveCriticalSection(&QueueLock);SetEvent(hQueueNotEmpty);return 0;
}// 消费者线程
DWORD WINAPI Consume(LPVOID lp)
{while (true){WaitForSingleObject(hQueueNotEmpty, INFINITE);EnterCriticalSection(&QueueLock);while (!Queue.empty()){int Data = Queue.front();Queue.pop();std::cout << "ID -> " << GetCurrentThreadId() << " Consume -> " << Data << std::endl;}if (bProduceFinished && Queue.empty()){LeaveCriticalSection(&QueueLock);break;}SetEvent(hQueueNotFull);LeaveCriticalSection(&QueueLock);Sleep(rand() % 100);}return 0;
}int main()
{// 初始同步对象InitializeCriticalSection(&QueueLock);hQueueNotFull = CreateEvent(NULL, TRUE, TRUE, NULL);hQueueNotEmpty = CreateEvent(NULL, FALSE, FALSE, NULL);// 启动执行线程hThreads[0] = CreateThread(NULL, 0, Produce, NULL, 0, NULL);hThreads[1] = CreateThread(NULL, 0, Produce, NULL, 0, NULL);hThreads[2] = CreateThread(NULL, 0, Consume, NULL, 0, NULL);// 等待线程结束WaitForMultipleObjects(3, hThreads, TRUE, INFINITE);// 释放对象资源DeleteCriticalSection(&QueueLock);for (auto i : hThreads) { CloseHandle(i); }CloseHandle(hQueueNotFull);CloseHandle(hQueueNotEmpty);return 0;
}

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

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

相关文章

Python静态类型检查工具库之mypy使用详解

概要 在 Python 开发中,类型错误是常见的问题,尤其在大型项目中,类型错误可能导致代码难以调试和维护。为了提高代码的可靠性和可维护性,静态类型检查工具如 mypy 应运而生。mypy 是一个静态类型检查工具,它通过在 Python 代码中添加类型注释,实现编译时的类型检查,帮助…

【数据库】MySQL基本操作语句

目录 一、SQL语句 1.1 SQL分类 1.2 SQL语言规范 1.3 数据库对象与命名 1.3.1 数据库的组件(对象)&#xff1a; 1.3.2 命名规则&#xff1a; 1.4 SQL语句分类 二、基本命令 2.1 查看帮助信息 2.2 查看支持的字符集 2.3 查看默认使用的字符集 2.4 修改默认字符集 2.5…

【Python画图-seaborn驯化】一文学会seaborn画因子变量图catplot函数使用技巧

【Python画图-seaborn驯化】一文学会seaborn画因子变量图catplot函数使用技巧 本次修炼方法请往下查看 &#x1f308; 欢迎莅临我的个人主页 &#x1f448;这里是我工作、学习、实践 IT领域、真诚分享 踩坑集合&#xff0c;智慧小天地&#xff01; &#x1f387; 免费获取相关内…

人工智能项目论文复现

文章目录 &#xff08;一&#xff09;技术学习任务Ⅰ、机器学习之聚类1、基本介绍概念2、聚类分析基本介绍3、K均值聚类4、K近邻分类模型(KNN)5、均值漂移聚类6、代码实现7、上述三种算法总结 Ⅱ、机器学习其他常用技术1、决策树基本知识2、异常检测概念3、主成分分析4、决策树…

JVM:介绍

文章目录 一、什么是JVM二、JVM的功能1、解释和运行2、内存管理3、即时编译 三、常见的JVM四、Java虚拟机规范五、HotSpot发展历程 一、什么是JVM JVM的全称为Java Virtual Machine&#xff0c;Java虚拟机。本质上是一个运行在计算机上的程序&#xff0c;职责是运行Java字节码…

python办公自动化之分析日志文件

实现效果&#xff1a;根据关键字xx搜索关键字在日志的占比 前提&#xff1a;把日志保存到txt文件里 代码&#xff1a; # 读取准备好的日志文件log_file log_filelog_file.txt with open(log_file,r) as logfile:textlogfile.readlines() # 设置搜索的关键字&#xf…

相机,手机,行车记录仪及监控视频修复软件: Stellar Repair for Video

天津鸿萌科贸发展有限公司是 Stellar 系列数据恢复软件的授权代理商。 Stellar Repair for Video 是一款强大的工具&#xff0c;用于修复从主流相机品牌&#xff08;如佳能、尼康、索尼&#xff09;、行车记录仪、监控录像机、手机和其他视频设备拍摄的无法访问和损坏的视频。…

下载linux的吐槽

本来这几天放假了&#xff0c;想下一个linux玩一玩 教程&#xff08;我就是根据这个教程进行下载的&#xff0c;但是呢在进行修改BIOS 模式的 地方遇见了困难&#xff0c;也许是电脑修过的原因&#xff0c;我狂按F12 以及 FnF12都没有BIOS设置&#xff0c;只有一个让我选择用w…

面向过程编程详解

目录 前言1. 面向过程编程的定义2. 面向过程编程的特点2.1 过程和函数2.2 顺序执行2.3 全局变量2.4 控制结构 3. 面向过程编程的应用场景3.1 系统级编程3.2 科学计算3.3 小型项目 4. 面向过程编程的优缺点4.1 优点4.2 缺点 5. 代表性的编程语言5.1 C语言5.2 Pascal5.3 Fortran …

PHP数据结构之栈

本文由 ChatMoney团队出品 栈&#xff08;Stack&#xff09;是一种后进先出&#xff08;Last In First Out, LIFO&#xff09;的数据结构&#xff0c;它只允许在一端&#xff08;称为栈顶&#xff09;进行插入和删除操作。栈的应用非常广泛&#xff0c;例如在编程语言的函数调用…

LLM推理优化技术方向小结

LLM推理优化我认为总共可以分为以下几个方面&#xff1a; 优化KV Cache MQAGQAMLA调度 Continuous batchingKIMI的调度系统Mooncake魔改模型结构或者魔改 attention 计算 MOE架构flash attentionpaged attention量化 AWQGPTQ其他角度 一次解码 n 个 token 来尽可能充分利用子回…

wget pip git下载失败报错解决

文章目录 前言wgetpipgit 前言 三种常用的工具wget pip git下载失败报错解决 wget wget身份认证报错&#xff1a; ERROR: cannot verify sourceforge.net’s certificate 解决&#xff1a; 增加 --no-check-certificate 选项 配置代理后wget报错&#xff1a; Proxy tunneli…

PMP 认证权威吗?对项目…业生涯的发展有帮助?

PMP认证到底权威吗&#xff1f; 首先在我看来&#xff0c;PMP认证是否权威要从各个角度进行综合考虑。入行这么多年个人也有不少的体会&#xff0c;那么我们就从多个角度进行分析一下&#xff0c;PMP认证的权威性与促进方面。 在深入探讨这个话题前&#xff0c;我分享一下近期…

DDR3 (四)

1 DDR3 8倍预取 DDR3相比DDR2外部IO时钟又提高了一倍&#xff0c;因此DDR3外部IO时钟是内核时钟的4倍&#xff0c;再加上双沿采样&#xff0c;因此DDR3可以实现8倍预取 2 DDR3 芯片位宽 DDR3使用8倍预取技术&#xff0c;指的是芯片位宽&#xff08;DQ数据线位宽&#xff09…

智慧产业应用实训实践基地-信息类专业实践实验室-嵌入式、物联网、移动互联网、云计算、大数据、人工智能、区块链实训室

智慧产业实践基地面向信息类专业群&#xff0c;以智慧灯杆、智慧交通、智慧设施在智慧产业中的实际实践为项目原型&#xff0c;软硬件开源、开放&#xff0c;海量的技术资料和实训课程。整个系统运用了嵌入式、物联网、移动互联网、云计算、大数据、人工智能、区块链等综合交叉…

uniapp中微信小程序——蓝牙连接并通信

蓝牙连接并与设备进行通信 已下是我在实现蓝牙功能中使用到的所有Api&#xff0c;当然微信小程序中还有很多我没有用到的Api&#xff0c;如果下面没有满足你需求的Api可以去官方文档查看。 初始化蓝牙模块 openBluetoothAdapter 开始搜寻附近的蓝牙外围设备。 startBluetoot…

Python爬虫开发实战,房屋售价数据分析,案例教程编程实例课程详解

一、引言 在当今信息爆炸的时代,数据已成为决策的重要依据。对于房地产市场而言,了解房屋售价的变动趋势、价格分布以及影响房屋售价的因素等,对于购房者、开发商以及政府政策制定者都具有重要意义。本文将通过Python爬虫技术,爬取房地产网站上的房屋售价数据,并进行深入的…

收藏!2024年程序员的实用神器_new relic idea

前言 Chat GPT的升级节奏让人们越来越惊讶的同时&#xff0c;也让大家感觉到了压力&#xff0c;在如此快节奏的互联网世界中&#xff0c;开发人员需要不断学习与更新知识&#xff0c;保持领先地位并高效地交付高质量软件。 无论是集成开发环境 (IDE)、版本控制系统、测试工具…

解决selenium手动下载驱动问题

解决selenium手动下载驱动问题 每次都需要手动下载驱动很头疼&#xff0c;今天发现一个可以自动下载最新驱动的包webdriver_manager&#xff0c;挺不错的 安装依赖包 pip install selenium pip install webdriver_manager from selenium import webdriver from selenium.webdr…

开源网安入选全景图,成为唯一覆盖“开发安全”全领域厂商

​7月4日&#xff0c;知名网络安全媒体数说安全正式发布了《2024年中国网络安全市场全景图》&#xff0c;本次全景图共收录了408家国内优秀的网络安全企业&#xff0c;旨在为网络安全行业主管部门、从业者、产品及服务的使用者和购买单位以及资本机构提供全面、精准且具参考价值…