C++同步技术——Mutex相关 (转)

2023-10-30

进程的互斥运行

  正常情况下,一个进程的运行一般是不会影响到其他正在运行的进程的。但是对于某些有特殊要求的如以独占方式使用串行口等硬件设备的程序就要求在其进程运行期间不允许其他试图使用此端口设备的程序运行的,而且此类程序通常也不允许运行同一个程序的多个实例。这就引出了进程互斥的问题。

  实现进程互斥的核心思想比较简单:进程在启动时首先检查当前系统是否已经存在有此进程的实例,如果没有,进程将成功创建并设置标识实例已经存在的标记。此后再创建进程时将会通过该标记而知晓其实例已经存在,从而保证进程在系统中只能存在一个实例。具体可以采取内存映射文件、有名事件量、有名互斥量以及全局共享变量等多种方法来实现。

      以互斥内核对象来保持线程同步可能用到的函数主要有CreateMutex()、OpenMutex()、ReleaseMutex()、WaitForSingleObject()和WaitForMultipleObjects()等。在使用互斥对象前,首先要通过CreateMutex()或OpenMutex()创建或打开一个互斥对象。

// 创建互斥量
HANDLE m_hMutex = CreateMutex(NULL, FALSE, "Sample07");
// 检查错误代码
if (GetLastError() == ERROR_ALREADY_EXISTS) {
 // 如果已有互斥量存在则释放句柄并复位互斥量
 CloseHandle(m_hMutex);
 m_hMutex = NULL;
 // 程序退出
 return FALSE;
}

  上面这段代码演示了有名互斥量在进程互斥中的用法。代码的核心是CreateMutex()对有名互斥量的创建。CreateMutex()函数可用来创建一个有名或无名的互斥量对象,其函数原型为:

HANDLE CreateMutex(
 LPSECURITY_ATTRIBUTES lpMutexAttributes, // 指向安全属性的指针
 BOOL bInitialOwner, // 初始化互斥对象的所有者
 LPCTSTR lpName // 指向互斥对象名的指针
);

  如果函数成功执行,将返回一个互斥量对象的句柄。如果在CreateMutex()执行前已经存在有相同名字的互斥量,函数将返回这个已经存在互斥量的句柄,并且可以通过GetLastError()得到错误代码ERROR_ALREADY_EXIST。可见,通过对错误代码ERROR_ALREADY_EXIST的检测可以实现CreateMutex()对进程的互斥。

        建立互斥体,用来同步。如果一个线程获取了互斥体,则要获取该互斥体的第二个线程将被挂起,直到第一个线程释放该互斥体。    

     参数 
lpMutexAttributes 
指向一个SECURITY_ATTRIBUTES结构的指针,这个结构决定互斥体句柄是否被子进程继承。     
bInitialOwner 
布尔类型,决定互斥体的创建者是否为拥有者 
lpName 
指向互斥体名字字符串的指针。互斥体可以有名字。 
互斥体的好处是可以在进程间共享


  参数bInitialOwner主要用来控制互斥对象的初始状态。一般多将其设置为FALSE,以表明互斥对象在创建时并没有为任何线程所占有。如果在创建互斥对象时指定了对象名,那么可以在本进程其他地方或是在其他进程通过OpenMutex()函数得到此互斥对象的句柄。OpenMutex()函数原型为:
 

HANDLE OpenMutex(
 DWORD dwDesiredAccess, // 访问标志
 BOOL bInheritHandle, // 继承标志
 LPCTSTR lpName // 互斥对象名
);

获得互斥对象

DWORD WaitForSingleObject( HANDLE hHandle,//互斥对象的句柄 DWORD dwMilliseconds//Time-out interval, in milliseconds.
//The function returns if the interval elapses,
//even if the object's state is nonsignaled.
//If dwMilliseconds is zero, the function tests the object's state and returns immediately.
//If dwMilliseconds is INFINITE, the function's time-out interval never elapses. );

如果第二个参数是0,则是测试对象的状态后立即返回

如果是INFINITE,则一直测试对象状态直到接受到信号


  当目前对资源具有访问权的线程不再需要访问此资源而要离开时,必须通过ReleaseMutex()函数来释放其拥有的互斥对象,其函数原型为:
 

BOOL ReleaseMutex(HANDLE hMutex);


  其唯一的参数hMutex为待释放的互斥对象句柄。

至于WaitForSingleObject()和WaitForMultipleObjects()等待函数在互斥对象保持线程同步中所起的作用与在其他内核对象中的作用是基本一致的,也是等待互斥内核对象的通知。但是这里需要特别指出的是:在互斥对象通知引起调用等待函数返回时,等待函数的返回值不再是通常的WAIT_OBJECT_0(对于WaitForSingleObject()函数)或是在WAIT_OBJECT_0到WAIT_OBJECT_0+nCount-1之间的一个值(对于WaitForMultipleObjects()函数),而是将返回一个WAIT_ABANDONED_0(对于WaitForSingleObject()函数)或是在WAIT_ABANDONED_0到WAIT_ABANDONED_0+nCount-1之间的一个值(对于WaitForMultipleObjects()函数)。以此来表明线程正在等待的互斥对象由另外一个线程所拥有,而此线程却在使用完共享资源前就已经终止。除此之外,使用互斥对象的方法在等待线程的可调度性上同使用其他几种内核对象的方法也有所不同,其他内核对象在没有得到通知时,受调用等待函数的作用,线程将会挂起,同时失去可调度性,而使用互斥的方法却可以在等待的同时仍具有可调度性,这也正是互斥对象所能完成的非常规操作之一。

  在编写程序时,互斥对象多用在对那些为多个线程所访问的内存块的保护上,可以确保任何线程在处理此内存块时都对其拥有可靠的独占访问权。下面给出的示例代码即通过互斥内核对象hMutex对共享内存快g_cArray[]进行线程的独占访问保护。下面给出实现代码清单:

// 互斥对象
HANDLE hMutex = NULL;
char g_cArray[10];
UINT ThreadProc18(LPVOID pParam)
{
 // 等待互斥对象通知
 WaitForSingleObject(hMutex, INFINITE);
 // 对共享资源进行写入操作
 for (int i = 0; i < 10; i++)
 {
  g_cArray[i] = 'a';
  Sleep(1);
 }
 // 释放互斥对象
 ReleaseMutex(hMutex);
 return 0;
}
UINT ThreadProc19(LPVOID pParam)
{
 // 等待互斥对象通知
 WaitForSingleObject(hMutex, INFINITE);
 // 对共享资源进行写入操作
 for (int i = 0; i < 10; i++)
 {
  g_cArray[10 - i - 1] = 'b';
  Sleep(1);
 }
 // 释放互斥对象
 ReleaseMutex(hMutex);
 return 0;
}
……
void CSample08View::OnMutex() 
{
 // 创建互斥对象
 hMutex = CreateMutex(NULL, FALSE, NULL);
 // 启动线程
 AfxBeginThread(ThreadProc18, NULL);
 AfxBeginThread(ThreadProc19, NULL);
 // 等待计算完毕
 Sleep(300);
 // 报告计算结果
 CString sResult = CString(g_cArray);
 AfxMessageBox(sResult);
}


  互斥对象在MFC中通过CMutex类进行表述。使用CMutex类的方法非常简单,在构造CMutex类对象的同时可以指明待查询的互斥对象的名字,在构造函数返回后即可访问此互斥变量。CMutex类也是只含有构造函数这唯一的成员函数,当完成对互斥对象保护资源的访问后,可通过调用从父类CSyncObject继承的UnLock()函数完成对互斥对象的释放。CMutex类构造函数原型为:

CMutex( BOOL bInitiallyOwn = FALSE, LPCTSTR lpszName = NULL, LPSECURITY_ATTRIBUTES lpsaAttribute = NULL );


  该类的适用范围和实现原理与API方式创建的互斥内核对象是完全类似的,但要简洁的多,下面给出就是对前面的示例代码经CMutex类改写后的程序实现清单:

// MFC互斥类对象
CMutex g_clsMutex(FALSE, NULL);
UINT ThreadProc27(LPVOID pParam)
{
 // 等待互斥对象通知
 g_clsMutex.Lock();
 // 对共享资源进行写入操作
 for (int i = 0; i < 10; i++)
 {
  g_cArray[i] = 'a';
  Sleep(1);
 }
 // 释放互斥对象
 g_clsMutex.Unlock();
 return 0;
}
UINT ThreadProc28(LPVOID pParam)
{
 // 等待互斥对象通知
 g_clsMutex.Lock();
 // 对共享资源进行写入操作
 for (int i = 0; i < 10; i++)
 {
  g_cArray[10 - i - 1] = 'b';
  Sleep(1);
 }
 // 释放互斥对象
 g_clsMutex.Unlock();
 return 0;
}
……
void CSample08View::OnMutexMfc() 
{
 // 启动线程
 AfxBeginThread(ThreadProc27, NULL);
 AfxBeginThread(ThreadProc28, NULL);
 // 等待计算完毕
 Sleep(300);
 // 报告计算结果
 CString sResult = CString(g_cArray);
 AfxMessageBox(sResult);
}


 

CreateMutex()、OpenMutex()和CloseHandle()的配对:

HANDLE hMutex = CreateMutex(..."mymutex"); 

HANDLE hMutex1 = OpenMutex(.."mymutex"); 
CloseHandle(hMutex1); 

CloseHandle(hMutex);

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++同步技术——Mutex相关 (转) 的相关文章

  • setlocale()用法笔记

    http www cnblogs com hnrainll archive 2011 05 07 2039700 html C 和 C 的标准库分别有自己的 locale 操作方法 C 标准库的 locale 设定函数是 setlocale
  • 【报告分享】快手磁力金牛达人商家成长白皮书-磁力金牛(附下载)

    摘要 过去品牌与达人主要通过合作带货模式实现双方营销增长 现在则转为以品牌自播 达人分销双线并行模式为核心 这不仅有利于沉淀品牌数据和品牌资产 也是帮助品牌在快手形成长期营销阵地的基础 同时品牌客户的引入和成长 也带来了平台货品的极大丰富
  • 搭建私有Nuget服务器(.Net Core框架)

    目录 概述 搭建nuget服务 Baget服务 服务器搭建后台 管理nuget包 设置私有nuget服务器地址 命令行 下载自己推送的包 概述 在私有服务器上搭建Nuget服务 本地打包推送nuget包 实现对 net core项目自定义包
  • 火狐浏览器安装插件,访问Github速度加快

    github 访问超级慢 使用火狐浏览器安装GitHub加速这个插件 访问github瞬间提速 firefox安装插件 打开火狐浏览器 选择右上角三这个按钮 展开的下拉菜单中选择设置 输入github加速 按下回车键 再次访问github网
  • 打砖块游戏代码

    if 0 作业 添加 打砖块的检测 消除砖块 提示1 给zk数组赋值可以消除砖块 提示2 循环检测 提示3 打掉了的 就别再检测了 提示4 注意看球碰撞板子的检测方式 endif include
  • Unity忽略特定物体碰撞

    忽略指定层碰撞 Editor gt project setting gt physics 选择需要发生碰撞的层 忽略两个collider 的碰撞 Physics IgnoreCollision Collider collider1 Coll
  • 关于html中,使用<a>标签跳转页面会刷新父页面的问题

    我想要实现点击图片跳转到指定页面的操作 于是在图片上写了一个超链接 上代码 a div title xxx div a 出现了一个问题 当点击图片在新标签页打开网页时 父页面会自动刷新 这就导致之前在父页面输入的内容全部丢失 解决办法 在h
  • Ubuntu(乌班图)修改阿里云镜像源详细步骤及安装gcc编译器

    1 首先备份本地的源 sudo cp etc apt sources list etc apt sources list bak 回车 输入密码 回车 注 非root用户需要使用sudo 放在句首 用来提升权限 提示 带 的用户是root用
  • string和byte[]的转换 (C#)

    string类型转成byte byte byteArray System Text Encoding Default GetBytes str 反过来 byte 转成string string str System Text Encodin
  • 刷爆力扣!反超对象!第一天!(两数之和)

    很简单的力扣第一题 之前做过 但是太久没做也是忘记得差不多啦 题目 给定一个整数数组 nums 和一个整数目标值 target 请你在该数组中找出 和为目标值 target 的那 两个 整数 并返回它们的数组下标 你可以假设每种输入只会对应
  • 一篇关于vue的入门的详细介绍

    目录 一 介绍 二 库和框架的区别 三 什么是MVVM模式 四 实例 4 1 Vue开发示例 4 2 双向数据绑定 4 3 生命周期 好啦 今天的分享就到这了 希望能够帮到你呢 一 介绍 Vue js是一种流行的JavaScript框架 用
  • 2021-04-14

    Leetcode 两数相加 给你两个 非空 的链表 表示两个非负的整数 它们每位数字都是按照 逆序 的方式存储的 并且每个节点只能存储 一位 数字 请你将两个数相加 并以相同形式返回一个表示和的链表 你可以假设除了数字 0 之外 这两个数都
  • PS 更换证件照背景色

    哈喽 各位小伙伴 今天我们来学习一下如何更换证件照背景色 常见证件照 常见的证件照一般有白色 蓝色和红色三种样式 我们拍证件照一般只拍一种 为了节省支出 其他两种颜色就需要我们自己调色处理了 蓝底变红底 这里以蓝底证件照为例 首先打开PS
  • java 浮点数 精度_Java中浮点数丢失精度的解决方案

    注 直接将double类型作为参数利用构造方法获得的BigDecimal对象也是不精确的 2 方法介绍 获取小数点后位数 int scale Returns the scale of this BigDecimal 注 涉及到无限小数的点后
  • HTTP协议介绍与HTTP请求详解

    HTTP 是什么 HTTP 全称为 超文本传输协议 是一种应用非常广泛的 应用层协议 所谓 超文本 的含义 就是传输的内容不仅仅是文本 比如 html css 这个就是文本 还可以是一些 其他的资源 比如图片 视频 音频等二进制的数据 HT
  • 数据导入与预处理

    数据预处理总述 etl 抽取 转换 加载 大数据项目开发流程 数据采集 数据预处理 数据存储 数据分析挖掘 数据可视化 背景 数据质量问题 准确性 完整性 一致性 可信性 可解释性 时效性 相关性 准确性 数据是正确的 数据存储在数据库中的
  • 无内鬼来点干货,银行java开发面试题(含答案)

    目录 前言 1 在多线程环境中使用HashMap会有什么问题 在什么情况下使用get 方法会产生无限循环 2 不重写Bean的hashCode 方法是否会对性能带来影响 3 对于一个不可修改的类 它的每个对象是不是都必须声明成final的

随机推荐

  • luci页面“save&apply”的实现分析

    页面上配置的 保存 应用 功能的实现 最终调用到 etc config ucitrack的配置文件 例如配置无线时 对应ucitrack配置文件中的config network option init network list affect
  • ThreadLocal的使用

    当使用ThreadLocal维护变量时 ThreadLocal为每个使用该变量的线程提供独立的变量副本 所以每一个线程都可以独立地改变自己的副本 而不会影响其它线程所对应的副本 演示代码 package com oa public clas
  • Python file"文件"常用方法(三):读+写+刷新-write()、writelines()、read()、readline()、readlines()、flush()

    一 write 方法 将字符串写入文件 返回的是写入的字符长度 write 方法可将任何字符串写入一个打开的文件 需要重点注意的是 Python字符串可以是二进制数据 而不是仅仅是文字 在文件关闭前或缓冲区刷新前 字符串内容存储在缓冲区中
  • Anaconda3 环境下安装Open3D(自学笔记)

    介绍 Open3D是一个开源库 支持快速开发处理3D数据的软件 Open3D的核心功能包括 3D数据结构 3D数据处理算法 场景重建 表面对齐 3D可视化 基于物理的渲染 PBR 支持PyTorch TensorFlow 支持GPU加速处理
  • Docker安装JDK(二)

    安装的两种方式 通过已有的镜像直接pull安装 自己通过dockerfile等命令打包一个镜像安装 此种方式我们到已有镜像满足不了自身需求时使用 本章是根据第一种方式安装的 根据文章docker安装指定版本的tag镜像得到安装JDK的Doc
  • verilog 学习笔记 —— 时序逻辑 Sequential Logics (Latches and Flip-Flops 锁存器和触发器)

    1 D flip flop D触发器 module top module input clk Clocks are used in sequential circuits input d output reg q Use a clocked
  • 轻松学会Java导出word,一篇文章就够了!

    很多小伙伴在工作中 可能又这样一个需求 根据word模板去填充数据 变成我们想要的word文档 这是很多刚进入职场的小白都会碰到的需求 当遇上这种需求 我们可以通过这篇文章要讲的poi tl 来做处理 导入依赖
  • Centos7 安装部署Kubernetes(k8s)集群过程

    1 系统环境 服务器版本 docker软件版本 CPU架构 CentOS Linux release 7 9 Docker version 20 10 12 x86 64 2 前言 如下图描述了软件部署方式的变迁 传统部署时代 虚拟化部署时
  • 用Node.js搭建一个简单Web服务器

    Node js是基于Chrome V8引擎的JavaScript运行时环境 它允许我们在服务器端运行JavaScript代码 这让我们可以用JavaScript构建Web服务器 处理请求和响应 我们一起探索了如何用Node js搭建一个简单
  • 数据结构——链表课后习题解答

    学习完链表 做了一遍题 码完代码 能跑的都跑了一遍 检验了一下 答案若有错误 欢迎指出 感谢 以下是题目和答案 以下题目若没有指出 全是用单向链表 目录 1 逆序一个链表 2 如何判断一个链表是否有环 3 求链表的中间节点 要求只用一重循环
  • 【speech&nlp】如何实现总体数据按照长短排序,同样长度数据随机排序

    在做speech nlp任务时 经常有这样一个需求 假设有一个数据集 有1000条数据 但是只有100种长度 所以必然存在某些数据是一样长的 我们想要让总体按照长短排序 但是同样长的数据要随机排序 经过了这个操作 再分batch 这样的效果
  • jmeter做接口压力测试_jmeter接口性能测试

    jmeter是apache公司基于java开发的一款开源压力测试工具 体积小 功能全 使用方便 是一个比较轻量级的测试工具 使用起来非常简单 因为jmeter是java开发的 所以运行的时候必须先要安装jdk才可以 jmeter是免安装的
  • 解决vscode找不到Python自定义模块,报错No module named ‘xxx‘

    笔者最近在学习python过程中 把在pycharm运行成功的项目放在vscode中 发现一些报错 比如找不到笔者自定义的模块 参考了一些说法与办法 现将解决方法记录于此 前言 vscode之所以找不到自定义模块 与其PYTHONPATH有
  • 将yolov5检测结果保存成json文件

    将yolov5检测结果保存成json文件 每帧图片对应一个json文件 json文件中包含图片名称 检测到的bbox信息 分类结果 中心坐标和置信度 函数json add以图片名 该图像内的所有bbox信息 以及bbox数量为输入 在yol
  • PCB画板(Altium Designer)

    b站学习视频 1 https www bilibili com video BV1ei4y1L7TU spm id from 333 999 0 0 这力荐 2 https www bilibili com video BV1tE411g7
  • 判断多边形凹凸

    任意给定一个多边形 判断它是凸还是凹 多边形的顶点以逆时针方向的序列来表示 include
  • 关于小程序中如何获取openid

    想要获取用户的openid首先要明白获取的过程 1 登录 2 发请求获取openid 实现 先定义一组数据 后面发请求获取openid时要的参数 一个是appid 一个是secret秘钥 这两个在注册开发者平台后可以查到 如下 global
  • 【Vulnhub系列】DC1

    文章目录 基本信息 实验过程 额外内容 使用CVE2014 3704添加管理账号 另一种查询具有root权限命令的find语句 下载地址 https www vulnhub com entry dc 1 1 292 基本信息 Kali 19
  • Counterfactual Zero-Shot and Open-Set Visual Recognition

    Counterfactual Zero Shot and Open Set Visual Recognition 1 Introduction 文献提出一个反事实框架 是由对不可见类的泛化来支撑的 作者基于反事实的一致性规则 反事实确实是基
  • C++同步技术——Mutex相关 (转)

    进程的互斥运行 正常情况下 一个进程的运行一般是不会影响到其他正在运行的进程的 但是对于某些有特殊要求的如以独占方式使用串行口等硬件设备的程序就要求在其进程运行期间不允许其他试图使用此端口设备的程序运行的 而且此类程序通常也不允许运行同一个