WIN32核心编程 - 线程操作(二) 同步互斥
- 公开视频 -> 链接点击跳转公开课程
- 博客首页 -> 链接点击跳转博客主页
目录
竞态条件
CriticalSection
Mutex
CriticalSection & Mutex
Semaphore
Event
竞态条件
-
多线程环境下,当多个线程同时访问或者修改同一个数据时,最终结果为线程执行的时许。
-
如果没有同步机制,会发生竞态条件,可能导致数据不准确,或者程序发生异常等。
#include <iostream>
#include <windows.h>DWORD g_Num = 0;DWORD WINAPI WorkThread(LPVOID lp)
{for (size_t i = 0; i < 10000000; i++){//g_Num++;__asm LOCK INC [g_Num] }return 0;
}int main()
{HANDLE hThread[2] = { 0 };hThread[0] = CreateThread(NULL, 0, WorkThread, NULL, 0, NULL);hThread[1] = CreateThread(NULL, 0, WorkThread, NULL, 0, NULL);WaitForMultipleObjects(2, hThread, TRUE, -1);std::cout << g_Num << std::endl;return 0;
}
CriticalSection
#include <iostream>
#include <windows.h>DWORD g_Num = 0;
CRITICAL_SECTION cs = { 0 };DWORD WINAPI WorkThread(LPVOID lp)
{for (size_t i = 0; i < 1000000; i++){// 进入临界区EnterCriticalSection(&cs);// TODOg_Num++;// 退出临界区LeaveCriticalSection(&cs);}return 0;
}int main()
{HANDLE hThread[2] = { 0 };// 初始临界区InitializeCriticalSection(&cs);hThread[0] = CreateThread(NULL, 0, WorkThread, NULL, 0, NULL);hThread[1] = CreateThread(NULL, 0, WorkThread, NULL, 0, NULL);WaitForMultipleObjects(2, hThread, TRUE, -1);std::cout << g_Num << std::endl;// 清理临界区DeleteCriticalSection(&cs);return 0;
}
Mutex
-
互斥体(Mutex),用于防止多个线程同时访问或修改共享资源。
-
同一时刻下只有一个线程可以拥有互斥体的所有权,如果一个线程拥有了互斥体的所有权,则其他请求该互斥体的线程将会被阻塞,直到互斥体权限释放。
-
创建互斥体 - CreateMutex
-
请求互斥体 - WaitForSingleObject
-
释放互斥体 - ReleaseMutex
#include <iostream>
#include <windows.h>HANDLE hMutex = 0;
DWORD g_Num = 0;DWORD WINAPI WorkThread(LPVOID lp)
{for (size_t i = 0; i < 100000; i++){WaitForSingleObject(hMutex, INFINITE);g_Num++;ReleaseMutex(hMutex);}return 0;
}int main()
{hMutex = CreateMutex(NULL, FALSE, NULL); HANDLE hThread1 = CreateThread(NULL, 0, WorkThread, NULL, 0, NULL);HANDLE hThread2 = CreateThread(NULL, 0, WorkThread, NULL, 0, NULL);WaitForSingleObject(hThread1, INFINITE);WaitForSingleObject(hThread2, INFINITE);CloseHandle(hThread1);CloseHandle(hThread2);CloseHandle(hMutex);std::cout << g_Num << std::endl;return 0;
}
CriticalSection & Mutex
-
临界区
-
共享资源的线程同步机制,临界区在同一进程的线程之间提供了互斥访问。
-
每个线程在访问共享资源之前必须先能够进入临界区,在访问结束后离开临界区,完成线程同步。
-
-
互斥体
-
线程同步机制,用来限制多个线程同时访问共享资源。
- 互斥体可以同步进程或者线程,且可以跨进程同步。
-
#include <iostream> #include <Windows.h>int main() {HANDLE hMutex = CreateMutex(NULL, FALSE, L"0xCC_Mutex");if (hMutex == NULL) return 0;if (GetLastError() == ERROR_ALREADY_EXISTS){MessageBox(NULL, L"禁止多开", L"错误", MB_OKCANCEL);return 0;}std::cout << "Game Start..." << std::endl;system("pause");CloseHandle(hMutex);return 0; }
-
-
性能
-
临界区在同一进程的线程中比互斥体更快。
-
-
功能
-
互斥体可以跨进程同步,但临界区只能够在同一个进程下的线程之间进行同步。
-
-
所有权
-
互斥体有严格的所有权要求,只有拥有互斥体权限的线程才能够释放它。
-
- 死锁
- 当线程在持有锁的情况下意外死亡(异常)
- 如果线程在持有临界区锁的情况下意外终结,这个锁不会被释放,导致其他等待该临界区的线程无法正常执行,造成死锁。
-
#include <iostream> #include <Windows.h>CRITICAL_SECTION CriticalSection = { 0 };DWORD WINAPI WorkThread(LPVOID lp) {EnterCriticalSection(&CriticalSection);printf("TID -> %d \r\n", GetCurrentThreadId());Sleep(5000);LeaveCriticalSection(&CriticalSection);return 0; }int main() {InitializeCriticalSection(&CriticalSection);HANDLE hThread1 = CreateThread(NULL, 0, WorkThread, NULL, 0, NULL);Sleep(1000);TerminateThread(hThread1, 1);HANDLE hThread2 = CreateThread(NULL, 0, WorkThread, NULL, 0, NULL);WaitForSingleObject(hThread2, INFINITE);DeleteCriticalSection(&CriticalSection);return 0; } - 如果线程在持有互斥体锁的情况下意外终结,Windows会自动释放其所有权,使得其他线程可以继续正常执行。
-
#include <iostream> #include <Windows.h>HANDLE hMutex = NULL;DWORD WINAPI WorkThread1(LPVOID lp) {WaitForSingleObject(hMutex, INFINITE);printf("TID -> %d \r\n", GetCurrentThreadId());Sleep(5000);TerminateThread(GetCurrentThread(), -1);//todoreturn 0; }DWORD WINAPI WorkThread2(LPVOID lp) {printf("Wait For Thread1 Leave\r\n");WaitForSingleObject(hMutex, INFINITE);printf("TID -> %d \r\n", GetCurrentThreadId());ReleaseMutex(hMutex);return 0; }int main() {hMutex = CreateMutex(NULL, FALSE, NULL);HANDLE hThread1 = CreateThread(NULL, 0, WorkThread1, NULL, 0, NULL);Sleep(1000);HANDLE hThread2 = CreateThread(NULL, 0, WorkThread2, NULL, 0, NULL);WaitForSingleObject(hThread2, INFINITE);CloseHandle(hMutex);CloseHandle(hThread1);CloseHandle(hThread2);return 0; }
Semaphore
-
信号量是一种同步对象,用于控制多个线程对共享资源的访问。它是一个计数器,用来表示可用资源的数量。当信号量的值大于0,它表示有资源可用;当值为0,表示没有可用资源。
-
等待:试图减少信号量的值。如果信号量的值大于0,减1并继续执行。如果信号量的值为0,则线程阻塞,直到信号量的值变为大于0。
-
释放:增加信号量的值。如果有其他线程因等待这个信号量而阻塞,它们中的一个将被唤醒。
-
-
创建信号量
-
在 Windows 系统中,使用
CreateSemaphore或CreateSemaphoreEx函数创建信号量。
-
-
等待(Wait)和释放(Release)信号量
-
等待信号量通常使用
WaitForSingleObject或WaitForMultipleObjects函数。 -
释放信号量使用
ReleaseSemaphore函数。
-
#include <iostream>
#include <Windows.h>#define MAX_COUNT_SEMAPHORE 3HANDLE g_SemapHore = NULL;
HANDLE g_hThreadArr[10] = { 0 };DWORD WINAPI WorkThread(LPVOID lp)
{WaitForSingleObject(g_SemapHore, INFINITE);for (size_t i = 0; i < 10; i++){std::cout << "COUNT -> " << (int)lp << std::endl;Sleep(500);}ReleaseSemaphore(g_SemapHore, 1, NULL);return 0;
}int main()
{g_SemapHore = CreateSemaphore(NULL, //安全属性MAX_COUNT_SEMAPHORE, //初始计数MAX_COUNT_SEMAPHORE, //最大计数NULL //信号名称);if (g_SemapHore == NULL){std::cout << GetLastError() << std::endl;return 1;}for (size_t i = 0; i < 10; i++){g_hThreadArr[i] = CreateThread(NULL,0,WorkThread,(LPVOID)i,0,NULL);}WaitForMultipleObjects(10, g_hThreadArr, TRUE, INFINITE);//closehandlereturn 0;
}
Event
-
在Windows编程中,事件是一种同步机制,用于在多个线程之间发送信号。事件对象可以是手动重置或自动重置。
-
手动重置事件(Manual Reset Event):当事件被设置(signaled)后,它将保持这个状态直到显式地被重置。这意味着多个等待该事件的线程都可以在事件被重置之前被唤醒。
-
自动重置事件(Auto Reset Event):当事件被一个等待的线程接收(signaled)后,系统会自动将事件状态重置为非信号状态(non-signaled)。这意味着每次只允许一个线程被唤醒。
-
-
创建事件
-
使用Windows API函数
CreateEvent可以创建一个事件对象 -
lpEventAttributes:指向安全属性的指针,如果设置为NULL,则使用默认安全性。 -
bManualReset:如果为TRUE,则创建一个手动重置事件,否则创建自动重置事件。 -
bInitialState:如果为TRUE,则初始状态为信号状态;如果为FALSE,则为非信号状态。 -
lpName:事件的名称。
-
-
设置事件(将事件状态设置为信号状态)使用
SetEvent函数 -
重置事件(将事件状态设置为非信号状态)使用
ResetEvent函数 -
等待事件 等待一个事件对象变为信号状态使用
WaitForSingleObject函数
#include <iostream>
#include <Windows.h>DWORD WINAPI WorkThread(LPVOID lp)
{HANDLE hEvent = *(HANDLE*)lp;std::cout << "Thread - " << GetCurrentThreadId() << " Waiting For Event" << std::endl;WaitForSingleObject(hEvent, INFINITE);std::cout << "Thread - " << GetCurrentThreadId() << " actived" << std::endl;return 0;
}int main()
{HANDLE hThreads[3] = { 0 };HANDLE hEvent = NULL;hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);if (hEvent == NULL) return 0;for (size_t i = 0; i < 3; i++){hThreads[i] = CreateThread(NULL, 0, WorkThread, &hEvent, 0, NULL);}Sleep(2000);SetEvent(hEvent);WaitForMultipleObjects(3, hThreads, TRUE, INFINITE);CloseHandle(hEvent);return 0;
}
相关文章:
WIN32核心编程 - 线程操作(二) 同步互斥
公开视频 -> 链接点击跳转公开课程博客首页 -> 链接点击跳转博客主页 目录 竞态条件 CriticalSection Mutex CriticalSection & Mutex Semaphore Event 竞态条件 多线程环境下,当多个线程同时访问或者修改同一个数据时,最终结果为线程执…...
web自动化(六)unittest 四大组件实战(京东登录搜索加入购物车)
Unittest框架 Unittest框架:框架测试模块测试管理模块测试统计模块,python的内置模块 import unittest Unittest框架四大组件: 1、TestCase 测试用例 2.TestFixture 测试用例夹具 测试用例需要执行的前置和后置 3.TestSuite 测试套件 把需要执行的测试用例汇总在一…...
鸿蒙语言基础类库:【@ohos.process (获取进程相关的信息)】
获取进程相关的信息 说明: 本模块首批接口从API version 7开始支持。后续版本的新增接口,采用上角标单独标记接口的起始版本。开发前请熟悉鸿蒙开发指导文档:gitee.com/li-shizhen-skin/harmony-os/blob/master/README.md点击或者复制转到。…...
华为笔试题
文章目录 1、数的分解2、字符串判断子串 1、数的分解 给定一个正整数n,如果能够分解为m(m > 1)个连续正整数之和, 请输出所有分解中,m最小的分解。 如果给定整数无法分解为连续正整数,则输出字符串"N"。 输入描述&a…...
【MySQL基础篇】函数及约束
1、函数 函数是指一段可以直接被另一段程序程序调用的程序或代码。 函数 - 字符串函数 MySQL中内置了很多字符串函数,常用的几个如下: 函数功能CONCAT(S1,S2,...,Sn)字符串拼接,将S1,S2,...,Sn拼接成一个字符串LOWER(str)将字符串str全部…...
YOLOv9报错:AttributeError: ‘list‘ object has no attribute ‘view‘
报错信息如下: red_distri, pred_scores torch.cat([xi.view(feats[0].shape[0], self.no, -1) for xi in feats], 2).split( AttributeError: ‘list’ object has no attribute ‘view’ 解决方法: 去yolov9/utils/loss_tal.py把167行代码更改&#…...
Bert入门-使用BERT(transformers库)对推特灾难文本二分类
Kaggle入门竞赛-对推特灾难文本二分类 这个是二月份学习的,最近整理资料所以上传到博客备份一下 数据在这里:https://www.kaggle.com/competitions/nlp-getting-started/data github(jupyter notebook):https://gith…...
【DFS(深度优先搜索)详解】看这一篇就够啦
【DFS详解】看这一篇就够啦 🍃1. 算法思想🍃2. 三种枚举方式🍃2.1 指数型枚举🍃2.2 排列型枚举🍃2.3 组合型枚举 🍃3. 剪枝优化🍃4. 图的搜索🍃5. 来几道题试试手🍃5.1 选…...
java-spring boot光速入门教程(超详细!!)
目录 一、引言 1.1 初始化配置 1.2 整合第三方框架 1.3 后期维护 1.4 部署工程 1.5 敏捷式开发 二、SpringBoot介绍 spring boot 2.1 搭建一个spring boot工程 2.2 使用idea创建项目 2.3 在线创建姿势 2.4 项目的目录结构 2.5 项目的运行方式 2.6 yml文件格式 2…...
一、Prometheus和Grafana搭建
一、服务端Prometheus二进制安装 https://prometheus.io/下载过慢可使用迅雷下载 tar -zxvf prometheus-2.53.0.linux-amd64.tar.gz启动 ./prometheus --config.fileprometheus.yml将其配置为系统服务: vim /usr/lib/systemd/system/prometheus.service[Unit] D…...
从零开始的python学习生活
pycharm部分好用快捷键 变量名的定义 与之前学习过的语言有所不同的是,python中变量名的定义更加的简洁 such as 整形。浮点型和字符串的定义 money50 haha13.14 gaga"hello"字符串的定义依然是需要加上引号,也不需要写;了 字符…...
MSP学习
一、迁移资源调研 完成导入,类似完成选型分析 离线工具调研 账单 二、迁移计划 1、 ecs 确认开始构建迁移环境后,平台将锁定当前标记的迁移资源范围及源端、目标端资源配置信息,并以此为迁移环境构建及迁移实施的数据依据 目标账号…...
生产力工具|Endnote X9如何自动更新文件信息
一、以EndNote X9.2版本为例,打开EndNote文献管理软件。 二、在菜单栏找到“Edit→Preferences...”,点击打开,弹出一个“EndNote Preferences”窗口。 三、进行设置 在打开的窗口左侧选择“PDF Handing”,右边会出现自动导入文献…...
【python】字典、列表、集合综合练习
1、练习1(字典) 字典dic,dic {‘k1’:‘v1’, ‘k2’: ‘v2’, ‘k3’: [11,22,33]} (1). 请循环输出所有的key dic {"k1": "v1", "k2": "v2", "k3": [11, 22, 33]} for k in dic.keys():print(k)k1 k2 k3(2). 请循环输…...
超融合服务器挂载硬盘--linux系统
项目中需要增加服务器的硬盘容量,通过超融合挂载了硬盘后,还需要添加到指定的路径下,这里记录一下操作步骤。 一:通过管理界面挂载硬盘 这一步都是界面操作,登录超融合控制云台后,找到对应的服务器&#…...
Kafka如何防止消息重复发送
Kafka 提供了几种方式来防止消息重复发送和处理。这些方式通常取决于生产者和消费者的设置和实现方式: 生产者端幂等性(什么是幂等性): 幂等性生产者:从 Kafka 0.11 版本开始引入了生产者端的幂等性支持。生产者可以通…...
数据库设计原则介绍
数据库设计是一个重要的过程,它涉及到创建一个逻辑结构来存储和管理数据。良好的数据库设计可以确保数据的完整性、一致性、性能和安全性。以下是一些关键的数据库设计原则: 1. 数据规范化 (Normalization) 目的:减少数据冗余、提高数据一致…...
反馈神经网络与不同类型的神经网络:BP神经网络,深度感知机,CNN,LSTM
反馈神经网络与不同类型的神经网络:BP神经网络,深度感知机,CNN,LSTM 在神经网络的研究和应用中,我们经常听到BP神经网络、深度感知机(MLP)、卷积神经网络(CNN)、长短期记…...
轮播图案例
丐版轮播图 <!DOCTYPE html> <html lang"zh-cn"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title> 基础轮播图 banner 移入移出</t…...
Spring 泛型依赖注入
Spring 泛型依赖注入,是利用泛型的优点对代码时行精简,将可重复使用的代码全部放到一个类之中,方便以后的维护和修改,同时在不增加代码的情况下增加代码的复用性。 示例代码: 创建实体类 Product package test.spri…...
基于算法竞赛的c++编程(28)结构体的进阶应用
结构体的嵌套与复杂数据组织 在C中,结构体可以嵌套使用,形成更复杂的数据结构。例如,可以通过嵌套结构体描述多层级数据关系: struct Address {string city;string street;int zipCode; };struct Employee {string name;int id;…...
未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?
编辑:陈萍萍的公主一点人工一点智能 未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战,在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…...
Linux应用开发之网络套接字编程(实例篇)
服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …...
Linux云原生安全:零信任架构与机密计算
Linux云原生安全:零信任架构与机密计算 构建坚不可摧的云原生防御体系 引言:云原生安全的范式革命 随着云原生技术的普及,安全边界正在从传统的网络边界向工作负载内部转移。Gartner预测,到2025年,零信任架构将成为超…...
Spring Boot+Neo4j知识图谱实战:3步搭建智能关系网络!
一、引言 在数据驱动的背景下,知识图谱凭借其高效的信息组织能力,正逐步成为各行业应用的关键技术。本文聚焦 Spring Boot与Neo4j图数据库的技术结合,探讨知识图谱开发的实现细节,帮助读者掌握该技术栈在实际项目中的落地方法。 …...
今日学习:Spring线程池|并发修改异常|链路丢失|登录续期|VIP过期策略|数值类缓存
文章目录 优雅版线程池ThreadPoolTaskExecutor和ThreadPoolTaskExecutor的装饰器并发修改异常并发修改异常简介实现机制设计原因及意义 使用线程池造成的链路丢失问题线程池导致的链路丢失问题发生原因 常见解决方法更好的解决方法设计精妙之处 登录续期登录续期常见实现方式特…...
MySQL 知识小结(一)
一、my.cnf配置详解 我们知道安装MySQL有两种方式来安装咱们的MySQL数据库,分别是二进制安装编译数据库或者使用三方yum来进行安装,第三方yum的安装相对于二进制压缩包的安装更快捷,但是文件存放起来数据比较冗余,用二进制能够更好管理咱们M…...
CRMEB 中 PHP 短信扩展开发:涵盖一号通、阿里云、腾讯云、创蓝
目前已有一号通短信、阿里云短信、腾讯云短信扩展 扩展入口文件 文件目录 crmeb\services\sms\Sms.php 默认驱动类型为:一号通 namespace crmeb\services\sms;use crmeb\basic\BaseManager; use crmeb\services\AccessTokenServeService; use crmeb\services\sms\…...
android RelativeLayout布局
<?xml version"1.0" encoding"utf-8"?> <RelativeLayout xmlns:android"http://schemas.android.com/apk/res/android"android:layout_width"match_parent"android:layout_height"match_parent"android:gravity&…...
用鸿蒙HarmonyOS5实现中国象棋小游戏的过程
下面是一个基于鸿蒙OS (HarmonyOS) 的中国象棋小游戏的实现代码。这个实现使用Java语言和鸿蒙的Ability框架。 1. 项目结构 /src/main/java/com/example/chinesechess/├── MainAbilitySlice.java // 主界面逻辑├── ChessView.java // 游戏视图和逻辑├──…...
