mutex和CRITICAL_SECTION,互斥和临界区
本文不没有任何知识可讲,只是帖上自己测试的结果。
想看底层原理的可以直接关闭。
不过对于急着要选方案的人,倒提供一些帮助。
先说一些无关紧要的废话:
====================================================================================================================================================
先说说为什么会有这篇文章。
我在做练习的时候,参考一些老代码,发现了CRITICAL_SECTION这个类型。以前没有用过。查了一下,三个要点:windows使用;互斥效果;比mutex快。
后来又翻了些网页查看两者的一些简介。很统一的结果,CRITICAL_SECTION比mutex快,而且Linux上没有类似的接口(注:可能是我搜索的方式不对,加上本人对Linux研究不多,所以没有找到)。
对于刚打算使用c++11制作全新技术接口版本的服务器的我来说,很遗憾啊,Linux没有。难道我只能用这种慢速的锁?而我又不想写太多差异化的代码,能用标准库最好,等到真的某个模块成为新能瓶颈的时候再针对某个模块在Linux上做差异处理。
所以我还是想使用标准库来完成这个事情。
于是,我搜索“CRITICAL_SECTION c++11”。
两篇很重要的文章出现在了搜索结果里,是因为这两篇文章而产生了本文。
https://stackoverflow.com/questions/23519630/are-there-c11-critical-sections
https://stackoverflow.com/questions/9997473/stdmutex-performance-compared-to-win32-critical-section
====================================================================================================================================================
第一篇文章的精要在:
虽然Linux上没有临界区这样的接口,而mutex又是需要陷入内核去处理的东西。但是呢这些都是规定,仅仅是为了兼容POSIX协议做的。而mutex慢主要是POSIX需要跨进程。但是呢,在不同的系统和版本上面,就可以有私人定制,就如同windows上的CRITICAL_SECTION。一旦我不再兼容POSIX,就可以做一些自己的花活。而同时在兼容POSIX的平台上,继续遵循POSIX的规定。
以上精要,你可以在第一个连接的第一个回复里面的追问里面得到。
这给我提供了一个很重要的信息:c++11是没有临界区这样的用法。而且mutex的跨进程也不是所有的系统和版本都需要的,仅仅是某些版本需要。在不需要的版本上std::mutex可能是有特殊的用法和优化可以媲美临界区。
总之,mutex和mutex不一样
有了这个想法,我决定自己写代码试试。
然而不幸的是,当我准备写的时候,我想,这种问题应该也会有其他人这样想吧,说不定能搜到呢?
在搜索结果里,我就看到了第二篇。
第二篇文章的精要在:
std::mutex慢。CRITICAL_SECTION更快。但是如果采用合理的方式来分割任务,两者可以达到几乎相同的效果。
第二篇文章是含有两个人的测试代码的。第一个人的测试代码是直接比对两种用法的时间差异。但是很遗憾,他使用的是vs2012。这个版本对c++11的支持并不算完美。第二个人的测试代码是将任务做了分割,分给不同的cpu,又延长了执行间隔,减少访问冲突。使用的是vs2013,这一传说中对c++11支持很完善的版本
看到这里,我有些冷,就不太想写测试代码了。原因是开发工具,人家已经更新到了一个合理的版本,其次在结构上进行了划分,而划分之后才打个平手。
似乎所有的结果都是唯一的。
但是!中间好几年了。万一有变化呢?即使没有,自己测试一下总归实在一些。所以还是自己做了个测试。结果很意外。
先说思路:
在同一进程中,开启4个线程,2个用std::mutext去抢,两个用CRITICAL_SECTION去抢;
两组方式各自使用自己组的变量;
只记录计算次数,不做结果正确判断;
以下是测试代码
#include <iostream>
#include <mutex>
#include <thread>
#include <Windows.h>
#include <chrono> using namespace std; mutex g_Mutex_Lock, g_Mutex_finish;
CRITICAL_SECTION g_CS_Lock, g_CS_finish;
uint64_t g_Mutext_Num = -;
uint64_t g_CS_Num = -;
const int32_t g_Count = ;
once_flag g_Mutex_flag, g_CS_flag;
chrono::time_point<chrono::system_clock> g_Mutex_StartTime, g_CS_StartTime;
int32_t g_Mutex_Complete = ;
int32_t g_CS_Complete = ; uint64_t Calculate(uint64_t num, int index)
{
if (index % )
{
return (num / 0x5555) * 0xaaaa;
}
else
{
return (num / 0x6666) * 0x9999;
}
} void mutexTimeStart()
{
g_Mutex_StartTime = chrono::system_clock::now();
} void mutexCalculate()
{
call_once(g_Mutex_flag, mutexTimeStart); for (int i = ; i < g_Count; ++i)
{
g_Mutex_Lock.lock();
g_Mutext_Num = Calculate(g_Mutext_Num, i);
g_Mutex_Lock.unlock();
}
g_Mutex_finish.lock();
++g_Mutex_Complete;
if ( == g_Mutex_Complete)
{
chrono::duration<double> elapsed_seconds = chrono::system_clock::now() - g_Mutex_StartTime;
printf("mutex finished use: %f\n", elapsed_seconds.count());
}
g_Mutex_finish.unlock();
} void csTimeStart()
{
g_CS_StartTime = chrono::system_clock::now();
} void csCalculate()
{
call_once(g_CS_flag, csTimeStart);
for (int i = ; i < g_Count; ++i)
{
EnterCriticalSection(&g_CS_Lock);
g_CS_Num = Calculate(g_CS_Num, i);
LeaveCriticalSection(&g_CS_Lock);
}
EnterCriticalSection(&g_CS_finish);
++g_CS_Complete;
if ( == g_CS_Complete)
{
chrono::duration<double> elapsed_seconds = chrono::system_clock::now() - g_CS_StartTime;
printf("cs finished use: %f\n", elapsed_seconds.count());
}
LeaveCriticalSection(&g_CS_finish);
} void main()
{
InitializeCriticalSection(&g_CS_Lock);
InitializeCriticalSection(&g_CS_finish); thread t3(csCalculate);
t3.detach();
thread t4(csCalculate);
t4.detach(); thread t1(mutexCalculate);
t1.detach();
thread t2(mutexCalculate);
t2.detach(); int tStop;
cin >> tStop;
}
main.cpp
测试环境:win10企业版(已经更新到最新)+vs2015企业版+i7-6700HQ(2.6G×8)
64位release版结果:

图中除最后一个外,都是循环1千万次的结果。最后一个是10亿次的结果。
再上一个64位debug版的1亿次的截图(原谅我没有等带10亿次的结果,你们不知道,我测试1千万的结果是n秒。然后头绕一热直接跳了两级,一运行,发现没出结果,然后一算,就傻了,关掉减个0)。

无论前面有多少经历,无论多少推测。结果胜过一切,我可以继续安心的、开心的使用std继续进行我的练习了。
本次测试结果:
1、性能不是瓶颈,不要考虑太多。优化都是在原有的基础上逐步修改改出来的成果,不是动手的时候,脑子就有现成的方案。何况性能并没有走到瓶颈。
2、没有什么比电脑跑出来的结果更靠谱。毕竟电脑才是所有理论知识最终产物的执行者。
3、随时间的推移,技术在改良。使用通用的接口,每次技术更替,你也在享受免费的红利。
最后,如果有朋友发现我的代码中存在影响测试结果的错误,请留言指出。我不想自己错了,还误导别人。
mutex和CRITICAL_SECTION,互斥和临界区的更多相关文章
- pthread mutex 进程间互斥锁实例
共享标志 定义 名称 描述 0 PTHREAD_PROCESS_PRIVATE 进程内互斥锁 仅可当前进程内共享 1 PTHREAD_PROCESS_SHARED 进程间互斥锁 多个进程间共享 第一个 ...
- Mutex 进程间互斥
学习Mutex的心得,不一定对,先记录一下. 同步技术分为两大类,锁定和信号同步. 锁定分为:Lock.Monitor 信号同步分为:AutoResetEvent.ManualResetEvent.S ...
- Linux内核互斥锁--mutex
一.定义: /linux/include/linux/mutex.h 二.作用及访问规则: 互斥锁主要用于实现内核中的互斥访问功能.内核互斥锁是在原子 API 之上实现的,但这对于内核用户是不可见 ...
- [Go] golang互斥锁mutex
1.互斥锁用于在代码上创建一个临界区,保证同一时间只有一个goroutine可以执行这个临界区代码2.Lock()和Unlock()定义临界区 package main import ( " ...
- 十二 windows临界区,其他各种mutex
一.windows临界区 类似于互斥量 == 临界区. 二.多次进入临界区 进入临界区(加锁): 离开临界区(解锁): 同一个线程中windows中相同临界区变量代表的临界区进入(entercirti ...
- 互斥量mutex简介
互斥量又称互斥锁.互斥量是一个可以处于两态之一的变量:解锁和加锁. 简介 编辑 如果不需要信号量的计数能力,有时可以使用信号量的一个简化版本,称为互斥量(mutex).互斥量仅仅适用于管理共享资源或一 ...
- Linux的线程同步对象:互斥量Mutex,读写锁,条件变量
进程是Linux资源分配的对象,Linux会为进程分配虚拟内存(4G)和文件句柄等 资源,是一个静态的概念.线程是CPU调度的对象,是一个动态的概念.一个进程之中至少包含有一个或者多个线程.这 ...
- Go 标准库 —— sync.Mutex 互斥锁
Mutex 是一个互斥锁,可以创建为其他结构体的字段:零值为解锁状态.Mutex 类型的锁和线程无关,可以由不同的线程加锁和解锁. 方法 func (*Mutex) Lock func (m *Mut ...
- C++多线程同步之Mutex(互斥量)
原文链接: http://blog.csdn.net/olansefengye1/article/details/53086141 一.互斥量Mutex同步多线程 1.Win32平台 相关函数和头文件 ...
随机推荐
- java在控制台输出空心正方形,菱形,空心菱形
使用for和if打印一个空心正方形 /*思路:要想打印一个5x5的空心正方形,首先它的第一横行和最后一行都是填满的,需要全部遍历出来,第二三四行和只有左右两条边是出来的,中间部分为空的.因此在打印第 ...
- 自定义VS程序异常处理及调试Dump文件(一)
自定义VS程序异常处理及调试Dump文件(一) 1. Dump文件 1. Dump文件介绍 Dump文件(Dump File),也叫转储文件,以.DMP为文件后缀.dump文件是进程在内存中的镜像文件 ...
- Java之面向对象概述,类,构造方法,static,主方法,对象
一.面向对象概述 面向过程 "面向过程"(Procedure Oriented)是一种以过程为中心的编程思想.这些都是以什么正在发生为主要目标进行编程,不同于面向对象的是谁在受影响 ...
- Java之面向对象例子(三) 多态,重写,重载,equals()方法和toString()方法的重写
重写(继承关系) 子类得成员方法和父类的成员方法,方法名,参数类型,参数个数完全相同,这就是子类的方法重写了父类的方法. 重载 在一个类里有两个方法,方法名是完全一样的,参数类型或参数个数不同. 例子 ...
- 如何在web项目中添加javamelody monitoring 监控。
1.在工程的maven pom中添加依赖javamelody-core <!-- monitoring监控 --><!-- https://mvnrepository.com/art ...
- (转)Spring 的 init-method 和 destory-method
背景:今天在项目中看到spring中bean在初始化和注销时候的方法定义,之前没有用过这种方式,在此记录下,方便后期查看! 关于在spring 容器初始化 bean 和销毁前所做的操作定义方式有三种: ...
- vue.js使用props在父子组件之间传参
本篇文章是我参考官方文档整理的,供大家参考,高手勿喷! prop 组件实例的作用域是孤立的.这意味着不能 (也不应该) 在子组件的模板内直接引用父组件的数据.要让子组件使用父组件的数据,我们需要通过子 ...
- 创建自己的代码片段(CodeSnippet)
前言 工作中经常会写一些重复的代码片段,如自动属性.for循环.Action等等,针对这种情况,VisualStudio已经给我们提供了一个非常方便的功能--代码片段,是我们可以简单的输入几个字母就能 ...
- Hbase单机安装部署
Hbase单机安装部署 http://blogxinxiucan.sh1.newtouch.com/2017/07/27/Hbase单机安装部署/ 下载Hbase Hbase官网下载地址 http:/ ...
- ExtJs的expand和collapse
最近在研究ExtJs的窗口组件(Ext.window),关于扩展显示expand和折叠显示collapse的一点心得记录一下,以便后查. var win2 = new Ext.window({ id ...