05C++11多线程编程之使用正确的共享代码案例引入互斥量mutex的概念、用法

2023-11-14

05C++11多线程编程之使用正确的共享代码案例引入互斥量mutex的概念、用法

1 共享代码案例概念分析

  • 1)网络游戏服务器。两个自己创建的线程,一个线程收集玩家命令(一个数字代表玩家发来的命令),并把命令写到一个队列中;另外一个线程从队列中取出玩家送来的命令,解析,然后执行玩家需要的动作。

  • 2)但是,很多时候我们可以利用该思想进行衍生。例如有一个回调函数分为上下线的玩家ID,我们需要处理这些触发回调的上下线玩家id。那么我们就可以将这些上下线作为switch的case 值,玩家id作为处理后续操作的变量先将他们保存在一个结构体,再push进队列。这样就可以新开一个线程进行处理。
    这个例子下:回调函数充当了push消息线程。并且将处理玩家id上下线的逻辑放到新线程中处理,这样做的好处是简化了直接在回调函数中处理,防止回调处理过长出现崩溃。
    注:回调函数的形参一般带有void *pUser,以便传入该处理消息类的对象。
    上面这种思想在开发中非常常见,很重要。

下面为了简单,所以使用第一种处理思想处理共享代码案例。这种类一般称之为消息分发类或者消息处理类。
使用list的原因:
list:频繁的按顺序插入和删除数据时效率高。vector容器随机的插入删除数据效率高!

在讲安全正确的共享代码案例之前,我们必须先引入互斥量的概念。

2 互斥量的概念

  • 1)互斥量作用:保护一段共享代码。
  • 2)互斥量是个类对象,理解成一把锁,多个线程尝试用lock()成员函数来加锁,只有一个线程能锁成功(成功的标志是lock()函数返回);如果没锁成功,那么这个流程卡在lock(),其它线程不断的尝试去锁这把锁头。
    互斥量使用要小心,保护数据不多也不能少,少了,没有达到保护的效果,多了,影响效率。

3 互斥量的用法

  • 1)步骤:先lock(),操作共享数据,unlock()。
  • 2)lock()与unlock()必须要成对使用,有lock()必然要有unlock(),每调用一次lock(),必然应该调用一次unlock()。不应该也不允许调用一次lock(),却调用了2次unlock(),这些非对称数量的调用都会导致代码不稳定或者阻塞甚至崩溃。并且很难排除。

代码:

#include<iostream>
#include<thread>
#include<string>
#include<vector>
#include<list>
#include<mutex>

using namespace std;

//准备用成员函数作为线程函数的方法写线程,成为消息处理类
class A{
public:
	//把收到的消息入到一个队列的线程
	void inMsgRecvQueue(){
		for (int i = 0; i < 10000; i++){
			cout << "inMsgRecvQueue()执行,插入一个元素" << i << endl;
			my_mutex.lock();
			//my_mutex.lock();//error,多次上锁程序崩溃
			msgRecvQueue.push_back(i); //存放消息
			my_mutex.unlock();
			//my_mutex.unlock();//error,多次解锁程序崩溃
		}
	}

	//将共享的代码放到一个函数处理,方便上锁解锁
	bool outMsgLULProc(int &command){
		my_mutex.lock();
		if (!msgRecvQueue.empty()){
			//my_mutex.lock();//必须在读msgRecvQueue.empty()之前上锁,防止多个线程都满足不为空,然后阻塞完后就进行消费,这是不行的
			int command = msgRecvQueue.front();
			msgRecvQueue.pop_front();
			my_mutex.unlock();  //所有分支都必须有unlock()
			return true;
		}
		my_mutex.unlock();
		return false;
	}

	//把数据从消息队列取出的线程
	void outMsgRecvQueue(){
		int command = 0;
		for (int i = 0; i < 10000; i++){
			bool result = outMsgLULProc(command);
			if (result == true){
				cout << "outMsgRecvQueue()执行,取出一个元素" << endl;
				//处理数据
				//这里有可能也有需要共享的代码段
			}
			else{
				//消息队列为空
				cout << "inMsgRecvQueue()执行,但目前消息队列中为空!" << i << endl;
			}
		}
		cout << "end!" << endl;
	}

private:
	std::list<int> msgRecvQueue;//容器(消息队列),代表玩家发送过来的命令。
	std::mutex my_mutex;
};

int main()
{
	A myobja;

	std::thread myOutMsgObj(&A::outMsgRecvQueue, &myobja);//第二个参数,地址,才能保证线程里用的是同一个对象
	std::thread myInMsgObj(&A::inMsgRecvQueue, &myobja);

	myOutMsgObj.join();
	myInMsgObj.join();

	cout << "主线程执行!" << endl;

	return 0;
}

正确结果:
在这里插入图片描述

两次上锁,一次解锁的错误结果(注Linux下的C接口两次上锁结果是会阻塞):
在这里插入图片描述

一次上锁,两次解锁的错误结果:
在这里插入图片描述
所以总结:C++凡是mutex的lock和unlock不成对调用,都会直接报上面的程序崩溃错误。其它的C语言可能会阻塞或者其它错误。

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

05C++11多线程编程之使用正确的共享代码案例引入互斥量mutex的概念、用法 的相关文章

  • Asp.net core默认路由

    简化版Startup code public void ConfigureServices IServiceCollection services services AddMvc public void Configure IApplica
  • 调用许多网络服务的最佳方式?

    我有 30 家子公司 每家都实施了他们的 Web 服务 使用不同的技术 我需要实现一个Web服务来聚合它们 例如 所有子公司的Web服务都有一个名为的Web方法GetUserPoint int nationalCode 我需要实现我的网络服
  • Nullable 是不可能的,为什么不呢? [复制]

    这个问题在这里已经有答案了 如果这是一个愚蠢的问题 请原谅 我正在尝试更好地理解 Net 中的 Nullable 类型 从我从 Microsoft 源代码 使用 ReSharper 中注意到的内容 我了解到 Nullable 是一个结构 而
  • EventHandler 应该始终用于事件吗?

    我一直在愉快地使用自定义委托类型和通用编写事件Action委托类型 没有真正考虑我在做什么 我有一些很好的扩展助手Action and EventHandler这使我倾向于使用那些预定义的委托类型而不是我自己的委托类型 但除此之外 除了惯例
  • 从另一个 FORM 中取回隐藏的 FORM

    我有两种形式Form1 and Form2 我正在打开Form2 from Form1 on button Click Form2 obj2 new Form2 this Visible false obj2 Show 然后我想回来Form
  • C# 和月历,选择多个日期

    我正在制作一个程序 可以帮助人们用 C 为某个部门 预订 订单 他们需要能够选择不同月份的多个日期 我更愿意拥有它 这样他们就可以单击一个日期 然后按住 Shift 键单击另一个日期以选择这两个日期之间的所有日期 并控制单击以进行单选 取消
  • 为什么在 C++ 中声明枚举时使用 typedef?

    我已经很多年没有写过任何 C 了 现在我正试图重新开始 然后我遇到了这个并考虑放弃 typedef enum TokenType blah1 0x00000000 blah2 0X01000000 blah3 0X02000000 Toke
  • 虚拟并行端口模拟器

    在我的计算机网络课程中 我们应该通过使用本机寄存器 例如使用 outportb 等命令 来学习并行端口编程 我没有并行端口 因为我住在 2011 年 但想练习这些程序 我使用 dosbox 安装了旧的 Turboc 3 IDE 有没有一个程
  • 关闭整数的最右边设置位

    我只需要关闭最右边的设置位即可 我的方法是找到最右边位的位置 然后离开该位 我编写这段代码是为了这样做 int POS int n int p 0 while n if n 2 0 p else break n n 2 return p i
  • 判断串口是普通COM还是SPP

    我正在寻找一种方法来确定 COM 是标准 COM 还是 SPP COM 也称为 COM 设备的电缆替换蓝牙适配器 我有一个可以在 USB COM gt USB 和蓝牙下工作的设备 并且蓝牙接口可以与 SPP 一起工作 我目前正在使用Syst
  • 检测 TextBox 中的 Tab 键按下

    I am trying to detect the Tab key press in a TextBox I know that the Tab key does not trigger the KeyDown KeyUp or the K
  • 为什么 std::function 不是有效的模板参数,而函数指针却是?

    我已经定义了名为的类模板CallBackAtInit其唯一目的是在初始化时调用函数 构造函数 该函数在模板参数中指定 问题是模板不接受std function作为参数 但它们接受函数指针 为什么 这是我的代码 include
  • 如何设置消息队列的所有者?

    System Messaging MessageQueue 类不提供设置队列所有权的方法 如何以编程方式设置 MSMQ 消息队列的所有者 简短的答案是 p invoke 对 windows api 函数的调用MQSetQueueSecuri
  • 编写具有多种类型的泛型扩展方法时的类型推断问题

    我正在为 IEnumerable 编写一个通用扩展方法 用于将对象列表映射到另一个映射对象列表 这就是我希望该方法的工作方式 IList
  • 在 C 语言中替换宏内的宏

    我正在尝试使代码部分可重用 我下面的评论片段没有达到我想要的效果 define NAME ABC define LOG SIZE NAME LEN 我想LOG SIZE决心ABC LEN 我尝试过使用 但没能让它发挥作用 LOG SIZE在
  • 选择 asp.net CheckBoxList 中的所有项目

    ASP NET 和 C 我想要一个带有 全选 项目的复选框列表 当这个特定项目是 已选择 所有其他都将被选择 也 当选择被删除时 这个项目 也将来自所有人 其他物品 选中 取消选中 任何其他项目只会有一个 对特定项目的影响 无论选择状态如何
  • 在 mvc4 中创建通用 mvc 视图

    我以前也提过类似的问题 没有得到答案 如何创建一个通用的 mvc4 视图 该视图可以显示传递给它的模型列表或单个模型 模型可以是个人 组织或团体 无论传递给它的是什么 如果您正在寻找类似的东西 model MyViewModel
  • 初始化列表在 VC10 中不起作用

    我在 VC 2010 中编写了这个程序 class class1 public class1 initializer list
  • 如何知道 HTTP 请求标头值是否存在

    我确信这很简单 但是却让我感到厌烦 我在 Web 应用程序中使用了一个组件 它在 Web 请求期间通过添加标头 XYZComponent true 来标识自身 我遇到的问题是 如何在视图中检查此组件 以下内容不起作用 if Request
  • IDisposable 的显式实现

    虽然有很多关于IDisposable在 SO 上找到 我还没有找到答案 我通常遵循这样的做法 当我的一个班级拥有一个IDisposable对象然后它也实现IDisposable并打电话Dispose在拥有的对象上 然而最近我遇到了一个类 它

随机推荐

  • 智能学习

    智能学习 MATLAB实现CS BP多变量时间序列预测 布谷鸟搜索算法优化BP神经网络 目录 智能学习 MATLAB实现CS BP多变量时间序列预测 布谷鸟搜索算法优化BP神经网络 预测效果 基本介绍 程序设计 参考资料 预测效果 基本介绍
  • HTML静态页面获取url参数和UserAgent

    目录 前言 原因 解决 1 静态页面获取url的参数 2 取useragent的值 3 测试页面 前言 接技术支持小伙伴信 有用户反馈app在华为设备上下载不了 以为是服务器覆盖的范围不够或服务器挂了 直到另一个客服同事发来一个录屏 基本知
  • 自己写ArrayList后的心得

    源码分析 ArrayList应该是Java工具类中最简单的一个 它的内部实现是一个数组 在首次加入元素时 ArrayList会创建一个默认大小的数组 之后的添加 删除 查询操作都是对该数组进行操作 而我自己写的ArrayList则是和Lin
  • 记录错误:FileNotFoundError: [WinError 3] 系统找不到指定的路径。: ‘E:\\CV_Paper_fuxian\\lesson\\B_VGG\\..\\Data\\tra

    撸代码发现错误 FileNotFoundError WinError 3 系统找不到指定的路径 E CV Paper fuxian lesson B VGG Data train 经过检查发现 是系统内文件夹名称设置错误 如果出现这样的错误
  • new与malloc

    1 属性 new delete是c 运算符 关键字 需要编译器支持 malloc free是库函数 需要头文件支持 2 参数 使用new操作符申请内存分配时无需指定内存块的大小 编译器会根据类型信息自行计算 而malloc需要显示的指出所需
  • java/php/net/python家庭财务管理系统设计

    本系统带文档lw万字以上 答辩PPT 查重 如果这个题目不合适 可以去我上传的资源里面找题目 找不到的话 评论留下题目 或者站内私信我 有时间看到机会给您发 管理员用例图 系统中的核心家庭是系统管理员 管理员登录后 通过管理员菜单来管理后台
  • 03. HTTP协议

    目录 HTTP协议 基本概念 请求 响应 请求头中最常见的 些重要内容 爬虫需要 响应头中 些重要的内容 请求方式 总结 HTTP协议 基本概念 协议 就是两个计算机之间为了能够流畅的进行沟通而设置的 个君子协定 常见的协议有TCP IP
  • firefly的使用

    https github com 9miao Firefly gitpython setup py install firefly admin py createproject myproject 就可以创建一个新的工程了 转载于 http
  • mac os 安装metasploit v5.0.23(msf)

    安装metasploit git clone https github com rapid7 metasploit framework git cd metasploit framework msfconsole 执行上面的命令时 报如下错
  • 台式机常见问题汇总

    1 第一步 必须安装硬盘 硬盘安装在中间 否则安装电源后 硬盘不好安装了 2 第二步 检查台式机的数据线 应该是给足的 3 开机启动后 电脑吱吱响 后来找到原因 硬盘四个固定角没有固定好 所以转起来震动噪音 4 硬盘安装时 用的螺丝是接触面
  • 太空狼人杀(Among US)只能QuickChat 更改年龄限制达到可以Free To chat方法

    Among us 不能自由聊天的解决方法 对于年龄数据被上传到服务器的账号 可能不适用 1 进入 C Users 你的账户名 AppData LocalLow InnerSloth Among Us playerPrefs 如果看不到App
  • centos 安装alien

    出处 http linux4you in install netapp oncommand system manger on centos 1 在root权限下执行命令 sudo su 2 安装alien需要的依赖包 yum y insta
  • springmvc源码学习(二十七)异步任务超时异常的执行流程

    目录 前言 一 示例 二 源码分析 总结 前言 本文分析异步任务出现超时及异常的情况时的处理流程 一 示例 设置超时时间为2s 但任务需要执行10s ApiOperation value test notes test GetMapping
  • zsh + oh-my-zsh 主题预览

    The Themes robbyrussell the default that Robby uses The rest of the themes in alphabetical order af magic afowler agnost
  • 区块链技术之哈希指针

    hello 大家好 我们第三期的区块链技术分享来啦 那么话不多说 我们开始吧 提起区块链 大家可能都会提到 不可篡改 但是为什么区块链不可篡改呢 先给出答案 这与区块链的数据结构哈希指针和默克尔树有关 那么我们今天先分享哈希指针相关的内容
  • cron linux_如何在Linux中使用cron

    cron linux 本文最初发布于2017年11月 现已更新以包含其他信息 成为系统管理员的挑战 其中有很多优点 之一是当您想睡觉时正在运行任务 例如 某些任务 包括定期重复执行的任务 需要在没有人使用计算机资源的情况下通宵运行或在周末运
  • 211和985区别:

    985工程 是在 211工程 的基础上 根据我国国防 民用 东 中 西部协调发展的原则而筛选出来的
  • 获取网页的html文本(用selenium+chrome headless进行js异步加载内容),返回BeautifulSoup的soup对象

    import requests from bs4 import BeautifulSoup from selenium import webdriver def gethtml url js False if js False return
  • 1.代码片断收集-数据拷贝效率问题

    上面是我创建的群聊 欢迎新朋友的加入 1 基本信息 mycode 收录一些简单的代码片段 Gitee com 克隆链接 mycode 收录一些简单的代码片段 目的 记录和收集一些常用的代码片段 同时也欢迎网友提交push申请 共同完善 开发
  • 05C++11多线程编程之使用正确的共享代码案例引入互斥量mutex的概念、用法

    05C 11多线程编程之使用正确的共享代码案例引入互斥量mutex的概念 用法 1 共享代码案例概念分析 1 网络游戏服务器 两个自己创建的线程 一个线程收集玩家命令 一个数字代表玩家发来的命令 并把命令写到一个队列中 另外一个线程从队列中