Mutex 和 Critical Section 的异同 - 表格形式,一目了然

简介:

MutexCritical Section都是主要用于限制多线程(Multithread)对全局或共享的变量、对象或内存空间的访问。下面是其主要的异同点(不同的地方用绿色表示)。

 

Mutex

Critical Section

性能和速度

慢。

Mutex 是内核对象,相关函数的WaitForSingleObject

ReleaseMutex)需要用户模式(User Mode)到内核模式(Kernel Mode)的转换,在x86处理器上这种转化一般要发费600个左右的 CPU指令周期。

快。

Critical Section本身不是内核对象,相关函数(EnterCriticalSectionLeaveCriticalSection)的调用一般都在用户模式内执行,在x86处理器上一般只需要发费9个左右的 CPU指令周期。只有当想要获得的锁正好被别的线程拥有时才会退化成和Mutex一样,即转换到内核模式,发费600个左右的 CPU指令周期。

能否跨越进程(Process)边界

可以

不可

定义写法

HANDLE hmtx;

CRITICAL_SECTION cs;

初始化写法

hmtx= CreateMutex (NULL, FALSE, NULL);

InitializeCriticalSection(&cs);

结束清除写法

CloseHandle(hmtx);

DeleteCriticalSection(&cs);

无限期等待的写法

WaitForSingleObject (hmtx, INFINITE);

EnterCriticalSection(&cs);

0等待(状态检测)的写法

WaitForSingleObject (hmtx, 0);

TryEnterCriticalSection(&cs);

任意时间等待的写法

WaitForSingleObject (hmtx, dwMilliseconds);

不支持

锁释放的写法

ReleaseMutex(hmtx);

LeaveCriticalSection(&cs);

能否被一道用于等待其他内核对象

可以(使用WaitForMultipleObjectsWaitForMultipleObjectsExMsgWaitForMultipleObjects MsgWaitForMultipleObjectsEx等等

不可

当拥有锁的线程死亡时

Mutex变成abandoned状态,其他的等待线程可以获得锁。

Critical Section的状态不可知(undefined),以后的动作就不能保证了。

自己会不会锁住自己

不会(对已获得的Mutex,重复调用WaitForSingleObject不会锁住自己。但最后你别忘了要调用同样次数的ReleaseMutex

不会(对已获得的Critical Section,重复调用EnterCriticalSection不会锁住自己。但最后你别忘了要调用同样次数的LeaveCriticalSection

 

下面是一些补充:

l         请先检查你的设计,把不必要的全局或共享对象改为局部对象。全局的东西越少,出问题的可能就越小。

l         每次你使用EnterCriticalSection时,请不要忘了在函数的所有可能返回的地方都加上LeaveCriticalSection。对于Mutex也同样。若你把这个问题和Win32 structured exceptionC++ exception一起考虑,你会发现问题并不是那么简单。自定义一个封装类可能是一种解决方案,以Critical Section为例的代码如下所示:

class csholder

{

    CRITICAL_SECTION *cs;

public:

    csholder(CRITICAL_SECTION *c): cs(c)

    { EnterCriticalSection(cs); }

    ~csholder() { LeaveCriticalSection(cs); }

};

 

CRITICAL_SECTION some_cs;

void foo()

{

    // ...

    csholder hold_some(&some_cs);

 

    // ... CS protected code here

 

    // at return or if an exception happens

    // hold_some's destructor is automatically called

}

l         根据你的互斥范围需求的不同,把MutexCritical Section定义为类的成员变量,或者静态类变量。

l         若你想限制访问的全局变量只有一个而且类型比较简单(比如是LONGPVOID型),你也可以使用InterlockedXXX系列函数来保证一个线程写多个线程读。

 

 

本文主要参照了Jeffrey Richter的《Programming Applications for Microsoft Windows, 4th Ed.》。

专注于企业信息化,最近对股票数据分析较为感兴趣,可免费分享股票个股主力资金实时变化趋势分析工具,股票交流QQ群:457394862

本文转自沧海-重庆博客园博客,原文链接:http://www.cnblogs.com/omygod/archive/2006/11/08/554524.html,如需转载请自行联系原作者
目录
相关文章
|
8月前
|
编译器 C#
C#.Net筑基-类型系统②常见类型 --record是什么类型?
`record`在C#中是一种创建简单、只读数据结构的方式,常用于轻量级数据传输。它本质上是类(默认)或结构体的快捷形式,包含自动生成的属性、`Equals`、`ToString`、解构赋值等方法。记录类型可以继承其他record或接口,但不继承普通类。支持使用`with`语句创建副本。例如,`public record User(string Name, int Age)`会被编译为包含属性、相等比较和`ToString()`等方法的类。记录类型提供了解构赋值和自定义实现,如密封的`sealed`记录,防止子类重写。
|
8月前
|
存储 C#
C#.Net筑基-类型系统②常见类型--结构体类型Struct
本文介绍了C#中的结构体(struct)是一种用户自定义的值类型,适用于定义简单数据结构。结构体可以有构造函数,能定义字段、属性和方法,但不能有终结器或继承其他类。它们在栈上分配,参数传递为值传递,但在类成员或包含引用类型字段时例外。文章还提到了`readonly struct`和`ref struct`,前者要求所有字段为只读,后者强制结构体存储在栈上,适用于高性能场景,如Span和ReadOnlySpan。
|
8月前
|
JavaScript
js开发:请解释什么是ES6的Symbol,以及它的用途。
ES6的Symbol数据类型创建唯一值,常用于对象属性键(防冲突)和私有属性。示例展示了如何创建及使用Symbol:即使描述相同,两个Symbol也不等;作为对象属性如`obj[symbol1] = 'value1'`;也可作枚举值,如`Color.RED = Symbol('red')`。
60 4
|
8月前
|
JavaScript 前端开发
js开发:请解释什么是事件委托(event delegation),并给出一个示例。
事件委托是JavaScript中优化事件处理的技术,通过绑定事件处理器到共享的父元素,利用事件冒泡机制来处理子元素的事件。这种方法能提升性能、简化代码并降低内存消耗。示例展示了如何在父元素上监听`click`事件,然后通过`event.target`识别触发事件的具体子元素(如`<li>`),实现对动态生成列表项的点击事件处理。
58 1
|
存储 Go
go语言中空struct{}的用途
在Go语言中,空的 `struct{}` 类型通常被用作占位符或者信号。它不占用任何内存空间,也不包含任何字段,因此它被用来表示一个没有任何数据的结构体。
103 2
|
存储 C# Windows
|
存储 C语言 C++
一篇就带你读懂关于block的变量捕获(capture)
一篇就带你读懂关于block的变量捕获(capture)
225 0
一篇就带你读懂关于block的变量捕获(capture)
|
程序员
Attribute(特性),怎么用才更好? —— 字段编号被误解了
  上一篇里(Attribute(特性),怎么用才更好? ),有人说,“坚决杜绝magic number ”,这个magic number指的就是字段编号吧,其实您误解了。   一提到字段编号,可能有些人的第一反应就是这样的用法:     Person1.2000020,或者Person1[2000020],或者ds[2000020]。
909 0
【基础】Attribute的妙用
如果您觉得文章对您有帮助,可以【打赏】博主或点击文章右下角【推荐】一下。您的鼓励是博主坚持原创和持续写作的最大动力!
737 0

热门文章

最新文章