【学习笔记】Windows 下线程同步之互斥锁

article/2025/9/17 16:47:57

目录

  • 前言
  • 环境
  • 简介
  • 相关函数
    • CreateMutex
    • Wait 函数
    • ReleaseMutex
    • CloseHandle
  • 其他
    • 互斥锁的名字
    • 未命名互斥锁的同步
    • 互斥锁的意外终止
    • 临界区对象
  • 示例
  • 参考

前言

  1. 本文所涉及的同步主要描述在 Windows 环境下的机制,和 Linux 中的同步机制有一定的联系,但注意并不完全相同。类似于,Windows 和 Linux 按照自己的方式实现了操作系统中同步机制的概念
  2. 本文记录的是 Windows 下的互斥锁同步机制,但在 Windows 的同步机制中,其中很多的概念和逻辑同样适用于事件(Event),信号量,计时器等其他同步机制

环境

  1. OS:win
  2. IDE:Visual Studio 2015

简介

  • 简介:互斥锁是一种同步对象,当没有任何线程拥有互斥锁时,互斥锁处于有信号(signaled)状态,当互斥锁被某个线程拥有,则它处于无信号状态(nonsignaled)。

    顾名思义,互斥锁就是一种为了达到访问共享资源而互斥目的的锁。比如生活中,公共厕所就是一种共享资源,公厕一次只能有一个人使用,使用者在使用的时候就会关门上锁,使用完之后需要开门释放锁。对于每个使用者来说,这个锁一次只能被一个人占有

  • 特点

    • 任何一个互斥锁,一次只能被一个线程拥有
    • 可以跨进程使用,即进程间同步
  • 适用场景:同步一些共享资源,比如共享内存(shared memory)

相关函数

CreateMutex

  1. 作用:创建或打开命名或未命名的互斥锁对象。如果某互斥锁已经被创建,当再次使用 CreateMutex 操做该互斥锁,实际的操作等效于 OpenMutex,但通过 GetLastError 会返回 ERROR_ALREADY_EXISTS 标识
  2. 语法
HANDLE CreateMutexA([in, optional] LPSECURITY_ATTRIBUTES lpMutexAttributes,[in]           BOOL                  bInitialOwner,[in, optional] LPCSTR                lpName
);
  1. 参数
    1. lpMutexAttributes,为 NULL 时,句柄不能被子进程继承
    2. bInitialOwner,为 true 时,创建该互斥锁的线程获取该互斥锁
    3. lpName,互斥锁的名字,为 NULL 时,为未命名互斥锁,关于未命名互斥锁如何传递见下方“未命名互斥锁的同步”

Wait 函数

  1. Wait 函数是一系列提供类似功能的等待函数(如 WaitForMultipleObjects),该函数的作用是请求某个互斥锁的使用权,若没有获取到,则阻塞
  2. 等待函数的返回值表明等待函数因为某些原因返回,而不是正常的互斥锁信号转换
  3. 多个线程等待互斥锁时,只有一个线程会被随机选择获取互斥锁

ReleaseMutex

  1. 作用:释放控制权,释放后,互斥锁变为有信号状态
  2. 语法
BOOL ReleaseMutex([in] HANDLE hMutex
);
  1. 参数:hMutex 是要释放的互斥锁句柄

CloseHandle

  1. 作用:关闭句柄,本文中即关闭互斥锁
    【注】除了使用 CloseHandle 手动关闭句柄外,当某个进程终止后,也会自动关闭句柄
    【注】CloseHandle 关闭当前线程中使用的句柄,但如果还有其他线程拥有该句柄,那么句柄对象并未真正关闭,只有当最后一个该对象被关闭,句柄才会真正关闭
    在这里插入图片描述

如图,只有当所有句柄均被关闭,互斥锁对象才会自动关闭

其他

互斥锁的名字

特别注意的是,互斥锁的名字和其他同步对象(如,事件,信号量)的名字位于相同的命名空间,因此如果互斥锁有名字为“ExampleName”,事件也有名字为“ExampleName”则发生冲突,通过 GetLastError 函数返回 ERROR_INVALID_HANDLE 错误。

更多关于内核对象命名空间的知识可以阅读参考中的链接。

未命名互斥锁的同步

  1. 命名的互斥锁我们可以很容易理解如何让两个或多个线程使用相同的互斥锁。而未命名的互斥锁要如何让系统中多个线程与同一个互斥锁产生联系呢,答案是通过线程间(或进程间)复制句柄或者父子句柄继承实现,这里我们主要讲一下复制句柄

  2. 复制句柄:通过该方法可以在两个进程之间传递句柄,但相比于命名句柄和父子继承的方式,这种方式是最麻烦的,它需要在创建句柄的进程和使用句柄的进程间进行通信(如,命名管道,命名共享内存),当然这一步 Windows 通过高层函数隐藏了底层实现的细节,也就是说,你只需要调用一个 DuplicateHandle 函数即可完成两个进程的通信。

    另一个需要注意的地方,复制的句柄本质上和源句柄是等同的,你可以理解为指针间的赋值,赋值过后的两个指针实际是指向的相同的区域,任何改变都会影响两个指针指向的区域,句柄也是如此。

  3. 语法

BOOL DuplicateHandle([in]  HANDLE   hSourceProcessHandle,[in]  HANDLE   hSourceHandle,[in]  HANDLE   hTargetProcessHandle,[out] LPHANDLE lpTargetHandle,[in]  DWORD    dwDesiredAccess,[in]  BOOL     bInheritHandle,[in]  DWORD    dwOptions
);
  1. 参数
    1. hSourceProcessHandle:源进程的句柄,该进程必须有 PROCESS_DUP_HANDLE 的接入权限。源句柄可以通过 GetCurrentProcess 获得
    2. hSourceHandle:要被复制的句柄,比如互斥锁句柄
    3. hTargetProcessHandle:目标进程的句柄,该进程必须有 PROCESS_DUP_HANDLE 的接入权限。目标句柄可以通过 OpenProcess 获得
    4. lpTargetHandle:注意它是一个指针,指向复制过来的句柄,“LP” 是 long pointer 的缩写
    5. dwDesiredAccess:新句柄的权限设置。一般通过复制得到的句柄的权限范围 ≤ 原句柄
    6. bInheritHandle:该句柄能否被继承
    7. dwOptions:一些可选的配置项,这里不展开

关于句柄复制并非本篇的重点,详细内容移步官方文档

互斥锁的意外终止

比如,当前拥有互斥锁的线程终止,而该线程并未释放互斥锁,此时互斥锁被标记为遗弃(abandoned),它表明互斥锁未被正确释放

其他等待该互斥锁的线程可以获取它,但对应的 wait 函数会返回 WAIT_ABANDONED 来表明互斥锁对象被遗弃,由此表明此时被互斥锁操控的共享资源处于未定义状态(undefined state)

临界区对象

临界区(critical section)对象提供类似与互斥锁的功能,区别在于临界区对象不提供进程间同步,只能提供同一进程中的线程的同步
【注】这里的临界区对象是 Windows 提供的一种用户模式下的线程同步机制,不完全等同于操作系统中的临界区这个概念

示例

在本示例中,我们启动两个进程,分别为 A process 和 B process。

A process 产生一个互斥锁,名为 MutexDemo,并且在产生时就获得该锁的使用权,之后就是执行使用共享资源的代码,然后释放互斥锁,最终关闭互斥锁句柄。

B process 打开名为 MutexDemo,获得 MutexDemo 的使用权后,执行使用共享资源的代码,然后释放互斥锁,最终关闭互斥锁句柄。

A process cpp

void MutexSynchronize()
{cout << "A thread: enter mutex creator" << endl;// create a mutex and initially get itHANDLE hMutex = CreateMutex(NULL, true, _TEXT("MutexDemo"));// Simulate execute business logiccout << "A thread: set data into shared memory" << endl;// release mutex, mutex becomes signaledReleaseMutex(hMutex);// close handleSleep(5000);		// wait B thread get mutex, because we cannot predict the execution order // of 	multiple processesCloseHandle(hMutex);
}

B process cpp

void MutexSynchronize()
{cout << "B thread: enter mutex opener" << endl;HANDLE hMutex = NULL;// wait A thread create mutex and open itwhile (hMutex == NULL){hMutex = OpenMutex(MUTEX_ALL_ACCESS, false, _TEXT("MutexDemo"));cout << "B thread: wait mutex" << endl;}// wait signaled mutexWaitForSingleObject(hMutex, INFINITE);// Simulate execute business logiccout << "B thread: get data from shared memory" << endl;// release mutex, mutex becomes signaledReleaseMutex(hMutex);// close handleCloseHandle(hMutex);
}

参考

  1. Synchronization
  2. 《Windows 核心编程》
  3. Process Security and Access Rights
  4. Thread Handles and Identifiers:what is pseudo handle

http://chatgpt.dhexx.cn/article/vBoDBbJX.shtml

相关文章

C++——互斥量

文章目录 一、基本知识二、独占互斥量mutex1.mutex的介绍2.mutex的成员函数3.实例演示 三、lock_guard和unique_lock的使用和区别四、递归互斥量recursive_mutex1.基本知识2.演示示例 五、带超时的互斥量std::timed_mutex和std::recursive_timed_mutex 一、基本知识 C11提供如…

Linux——什么是互斥与互斥锁

目录 一.前提&#xff1a;临界区 & 临界资源 二.什么是互斥 &#xff08;一&#xff09;.互斥概念 &#xff08;二&#xff09;.为什么需要互斥 三.互斥锁介绍 &#xff08;一&#xff09;.互斥锁的概念 &#xff08;二&#xff09;.互斥锁的使用 ①系统API接口 ②…

线程的互斥与同步

线程的互斥与同步 线程的互斥简单的抢票程序互斥量初始化互斥量销毁互斥量互斥量加锁和解锁 互斥量实现原理 可重入VS线程安全概念常见的线程不安全的情况常见的线程安全的情况常见不可重入的情况常见可重入的情况可重入与线程安全联系可重入与线程安全区别 死锁死锁四个必要条…

FreeRTOS个人笔记-互斥量

根据个人的学习方向&#xff0c;学习FreeRTOS。由于野火小哥把FreeRTOS讲得比较含蓄&#xff0c;打算在本专栏尽量细化一点。作为个人笔记&#xff0c;仅供参考或查阅。 配套资料&#xff1a;FreeRTOS内核实现与应用开发实战指南、野火FreeRTOS配套视频源码、b站野火FreeRTOS视…

C++ 互斥锁原理以及实际使用介绍

兄弟姐妹们&#xff0c;我又回来了&#xff0c;今天带来实际开发中都需要使用的互斥锁的内容&#xff0c;主要聊一聊如何使用互斥锁以及都有哪几种方式实现互斥锁。实现互斥&#xff0c;可以有以下几种方式&#xff1a;互斥量&#xff08;Mutex&#xff09;、递归互斥量&#x…

MySQL mutex互斥锁

在事务机制中&#xff0c;锁机制是为了保证高并发&#xff0c;数据一致性的重要实现方式。MySQL除了Innodb引擎层面的行锁&#xff0c;还有latch锁。latch锁的作用资源协调处理。包含表句柄&#xff0c;线程&#xff0c;cpu线程&#xff0c;内存池等。其保证非常短时间内快速处…

uCOSii中的互斥信号量

uCOSii中的互斥信号量 一、互斥型信号量项管理 (MUTUAL EXCLUSION SEMAPHORE MANAGEMENT) OSMutexAccept() 无条件等待地获取互斥型信号量 OSMutexCreate() 建立并初始化一个互斥型信号量 OSMutexDel() 删除互斥型信号量 OSMutexPend() 等待一个互斥型信号量 OSMutexPost…

互斥信号量

目录 1、Creat 2、Delete 3、Wait 4、Post 5、Statu 互斥信号量 在介绍二进制信号量时&#xff0c;曾讨论到如果二进制信号量创建时设置参数 bInitValue 为TRUE&#xff0c;则可以用于互斥访问共享资源。实际上&#xff0c;SylixOS 的二进制信号量实现的互斥性是将一个变量…

UCOS-III 互斥量

互斥量 一、互斥量基本概念二、互斥量优先级继承机制三、互斥量应用场景四、互斥量运作机制五、互斥量创建流程1、定义互斥量2、创建互斥量 六、互斥量接口函数1、创建互斥量函数OSMutexCreate()2、删除互斥量函数 OSMutexDel()3、获取互斥量函数 OSMutexPend()4、释放互斥量函…

互斥量知识

文章目录 互斥量1、基本概念2、互斥量的优先级继承机制3、互斥量应用场景4、互斥量运行机制5、互斥量控制块6、互斥量函数接口&#xff08;1&#xff09;互斥量创建函数 xSemaphoreCreateMutex()&#xff08;2&#xff09;递归互斥量创建函数 xSemaphoreCreateRecursiveMutex()…

同步和互斥

同步和互斥 竞争与协作 在单核 CPU 系统里&#xff0c;为了实现多个程序同时运行的假象&#xff0c;操作系统通常以时间片调度的方式&#xff0c;让每个进程执行每次执行一个时间片&#xff0c;时间片用完了&#xff0c;就切换下一个进程运行&#xff0c;由于这个时间片的时间很…

多线程的同步与互斥(互斥锁、条件变量、读写锁、自旋锁、信号量)

文章目录 一、同步与互斥的概念二、互斥锁&#xff08;同步&#xff09;三、条件变量&#xff08;同步&#xff09;1、线程的条件变量实例12、线程的条件变量实例23、虚假唤醒(spurious wakeup) 四、读写锁&#xff08;同步&#xff09;五、自旋锁&#xff08;同步&#xff09;…

同步和互斥区别

互斥的概念 由于多线程执行操作共享变量的这段代码可能会导致竞争状态&#xff0c;因此我们将此段代码称为临界区&#xff08;critical section&#xff09;&#xff0c;它是访问共享资源的代码片段&#xff0c;一定不能给多线程同时执行。 我们希望这段代码是互斥&#xff0…

操作系统——互斥的定义及实现

一、进程互斥的定义 所谓进程互斥,指的是对某个系统资源,一个进程正在使用它,另外一个想用它的进程就必须等待,而不能同时使用 。进程互斥是多道程序系统中进程间存在的一种源于资源共享的制约关系,也称间接制约关系,主要是由被共享资源的使用性质所决定的。 二、互斥…

Fisher判别分析详解

Fisher判别分析 将高维度空间的样本投影到低维空间上&#xff0c;使得投影后的样本数据在新的子空间上有最小的类内距离以及最大的类间距离&#xff0c;使得在该子空间上有最佳的可分离性 可以看出右侧投影后具有更好的可分离性。 Fisher判别分析和PCA差别 刚学完感觉两个很…

基于spss的多元统计分析 之 聚类分析+判别分析(2/8)

实验目的&#xff1a; 1&#xff0e;掌握聚类分析及判别分析的基本原理&#xff1b; 2&#xff0e;熟悉掌握SPSS软件进行聚类分析及判别分析的基本操作&#xff1b; 3&#xff0e;利用实验指导的实例数据&#xff0c;上机熟悉聚类分析及判别分析方法。 实验前预习&#xff1a;…

机器学习——线性判别分析

目录 线性判别分析 LDA的降维过程 案例&#xff1a;鸢尾花(Iris) 代码演示 数据集 局部线性嵌入 线性判别分析 线性判别分析&#xff08;LDA&#xff09;是一种有监督的线性降维算法。与PCA不同&#xff0c;LDA是为了使降维后的数据点尽可能地容易被区分。 线性判别分析…

MATLAB判别分析例题,判别分析的matlab实现案例.doc

判别分析的matlab实现案例.doc 读取EXAMP10_01XLS中数据&#xff0c;进行距离判别读取数据读取文件EXAMP10_01XLS的第1个工作表中C2F51范围的数据&#xff0c;即全部样本数据&#xff0c;包括未判企业SAMPLEXLSREAD EXAMP10_01XLS , , C2F51 读取文件EXAMP10_01XLS的第1个工作…

SAS数据分析之判别分析

判别分析与聚类分析有非常类似的特性&#xff0c;因此&#xff0c;在多数数据分析的教材中&#xff0c;这两章是一前一后出现的&#xff0c;简而言之&#xff0c;聚类分析&#xff0c;其实是判别分析的基础&#xff0c;即在聚类分析的基础上&#xff0c;总结出各类的权值&#…

线性判别分析

线性判别分析&#xff08;LDA&#xff09;是一种经典的线性学习方法。其思想是&#xff1a;给定训练样例集&#xff0c;设法将样例投影到一条直线上&#xff0c;使得同类样例的投影点尽可能接近、异类样例的投影点尽可能远离。如图所示的二分类示意图&#xff1a; 损失函数的…