一、关键段CS 和 互斥量Mutex 的相同点:都有线程拥有权

关键段和互斥量都有线程拥有权,即可以被一个线程拥有。在 前面讲关键段CS的文章中有说到,关键段结构体的第四个参数保存着拥有该关键段的线程的句柄,具体如下:


typedef struct _RTL_CRITICAL_SECTION {
PRTL_CRITICAL_SECTION_DEBUG DebugInfo; //
// The following three fields control entering and exiting the critical
// section for the resource
// LONG LockCount;
LONG RecursionCount;
HANDLE OwningThread; // from the thread's ClientId->UniqueThread
HANDLE LockSemaphore;
ULONG_PTR SpinCount; // force size on 64-bit systems when packed
} RTL_CRITICAL_SECTION, *PRTL_CRITICAL_SECTION;
  • 第一个参数:PRTL_CRITICAL_SECTION_DEBUG DebugInfo; 调试的时候用的,先不做介绍。

  • 第二个参数:LONG LockCount; 初始化为-1,n表示有n个线程在等待。

  • 第三个参数:LONG RecursionCount; 表示该关键段的拥有线程对此资源获得关键段次数,初为0。

  • 第四个参数:HANDLE OwningThread; 即拥有该关键段的线程句柄

  • 第五个参数:HANDLE LockSemaphore; 实际上是一个自复位事件。

  • 第六个参数:ULONG_PTR SpinCount; 旋转锁的设置,用于多处理器。

现在我们来分析以下程序:


#include<iostream>
#include <windows.h>
using namespace std; const unsigned int THREAD_NUM = 10;
unsigned int g_Count = 0;
CRITICAL_SECTION cs;
DWORD WINAPI ThreadFunc(LPVOID); int main()
{
InitializeCriticalSection(&cs);
HANDLE hThread[THREAD_NUM];
for (int i = 0; i < THREAD_NUM; i++)
{
EnterCriticalSection(&cs); // 进入关键段,执行这一句时主线程就获得了这个关键段的拥有权。
hThread[i] = CreateThread(NULL, 0, ThreadFunc,0, 0, NULL);
}
WaitForMultipleObjects(THREAD_NUM, hThread,true,INFINITE);
cout << THREAD_NUM << " 个线程全部返回" << endl; return 0;
} DWORD WINAPI ThreadFunc(LPVOID p)
{
LeaveCriticalSection(&cs); // 离开关键段
Sleep(50);
EnterCriticalSection(&cs); // 进入关键段
cout<<"g_Count 的值为:"<<g_Count++<<endl;
LeaveCriticalSection(&cs); // 离开关键段
Sleep(50); return 0;
}

如下图所示加上两个断点进行调试,正常来说程序应该是依次经过两个断点,但是调试时我们发现,程序会多次重复进入第一个断点,这是因为执行到第一个断点式时主线程就获得了这个关键段的拥有权。

同样地,Mutex也拥有线程所有权,需要了解互斥量看这里。和上面一样,我们写这样一个程序


#include <iostream>
#include <windows.h>
using namespace std; const unsigned int THREAD_NUM = 10;
unsigned int g_Count = 0;
CRITICAL_SECTION cs;
HANDLE g_Mutex;
DWORD WINAPI ThreadFunc(LPVOID); int main()
{
InitializeCriticalSection(&cs);
g_Mutex = CreateMutex(NULL, false, NULL); //初始化互斥量为触发状态
HANDLE hTread[THREAD_NUM];
for (int i = 0; i < THREAD_NUM;i++)
{
WaitForSingleObject(g_Mutex, INFINITE); //等待互斥量触发
hTread[i] = CreateThread(NULL, 0, ThreadFunc, 0, 0, NULL);
}
WaitForMultipleObjects(THREAD_NUM, hTread, true, INFINITE);
cout << THREAD_NUM << " 个线程全部返回" << endl;
return 0;
} DWORD WINAPI ThreadFunc(LPVOID p)
{
//ReleaseMutex(g_Mutex);
Sleep(50);
EnterCriticalSection(&cs); // 进入关键段
cout << "g_Count 的值为:" << g_Count++ << endl;
LeaveCriticalSection(&cs); // 离开关键段
Sleep(50);
ReleaseMutex(g_Mutex); //触发互斥量
return 0;
}

同样地,我们在程序中下两个断点,同样地程序会不经过第二个断点,而重复经过第一个断点。

前面关键段和互斥量两篇文章我们说了关键段CS和互斥量Mutex不能做到线程同步,只能做到临界资源互斥访问,就是因为,他它们都有线程拥有权的原因。

二、关键段CS 和 互斥量Mutex 的不同点:由于互斥量常用于多进程之间的线程互斥,所以它比关键段还多一个很有用的特性——“遗弃”情况的处理。

看下面的程序:

程序一:


#include <stdio.h>
#include <windows.h> const char MutexName[] = "MyMutex"; //互斥量名字 int main()
{
HANDLE hMutex = CreateMutex(NULL, TRUE, MutexName); //创建互斥量并初始化为未触发状态
printf("互斥量已经创建,按任意键触发\n");
getch();
exit(0); //在互斥量触发前退出程序。
//ReleaseMutex(hMutex); // 触发互斥量
printf("互斥量已经被触发\n");
CloseHandle(hMutex);
return 0;
}

程序二:


#include <stdio.h>
#include <windows.h> const char MutexName[] = "MyMutex"; //互斥量名字 int main()
{
HANDLE hMutex = OpenMutex(MUTEX_ALL_ACCESS, TRUE, MutexName); //打开互斥量 if (NULL != hMutex)
{
printf("打开互斥量成功,等待互斥量被触发\n");
DWORD mRes = WaitForSingleObject(hMutex, INFINITE); // 等待互斥量被触发
if (WAIT_ABANDONED == mRes) //判断互斥量是否被遗弃
{
printf("互斥量被遗弃。\n");
}
//printf("互斥量已经被触发\n");
}
else
{
printf("互斥量打开失败。\n");
} CloseHandle(hMutex);
return 0;
}

先运行,程序一,然后运行程序二,如下图所示。

此时在,程序一中按任意键,使程序一在互斥量未触发之前退出,程序二输出如下:

这篇是边学边写出来的可能有不正确的地方,欢迎指出!!!!!

windows多线程(六) 互斥量Mutex与关键段CriticalSection比较的更多相关文章

  1. windows多线程同步--互斥量

    关于互斥量的基本概念:百度百科互斥量 推荐参考博客:秒杀多线程第七篇 经典线程同步 互斥量Mutex 注意:互斥量也是一个内核对象,它用来确保一个线程独占一个资源的访问.互斥量与关键段的行为非常相似, ...

  2. 多线程相关------互斥量Mutex

    互斥量(Mutex) 互斥量是一个可以处于两态之一的变量:解锁和加锁.只有拥有互斥对象的线程才具有访问资源的权限.并且互斥量可以用于不同进程中的线程的互斥访问. 相关函数: CreateMutex用于 ...

  3. 总结windows多线程同步互斥

    windows多线程同步互斥--总结 我的windows多线程系列文章: windows多线程--原子操作 windows多线程同步--事件 windows多线程同步--互斥量 windows多线程同 ...

  4. windows多线程同步互斥--总结

    我的windows多线程系列文章: windows多线程--原子操作 windows多线程同步--事件 windows多线程同步--互斥量 windows多线程同步--临界区 windows多线程同步 ...

  5. windows多线程(五) 互斥量 Mutex

    一.互斥量 互斥量是windows的一个内核对象,互斥量与关键段的作用相似,可以用来确保全局资源的互斥访问.并且互斥量可以用在不同的进程中的线程互斥访问全局资源. 二.相关函数说明 使用互斥量Mute ...

  6. 转--- 秒杀多线程第七篇 经典线程同步 互斥量Mutex

    阅读本篇之前推荐阅读以下姊妹篇: <秒杀多线程第四篇一个经典的多线程同步问题> <秒杀多线程第五篇经典线程同步关键段CS> <秒杀多线程第六篇经典线程同步事件Event& ...

  7. [一个经典的多线程同步问题]解决方案三:互斥量Mutex

    本篇通过互斥量来解决线程的同步,学习其中的一些知识. 互斥量也是一个内核对象,它用来确保一个线程独占一个资源的访问.互斥量与关键段的行为非常相似,并且互斥量可以用于不同进程中的线程互斥访问资源.使用互 ...

  8. 多线程面试题系列(7):经典线程同步 互斥量Mutex

    前面介绍了关键段CS.事件Event在经典线程同步问题中的使用.本篇介绍用互斥量Mutex来解决这个问题. 互斥量也是一个内核对象,它用来确保一个线程独占一个资源的访问.互斥量与关键段的行为非常相似, ...

  9. 秒杀多线程第七篇 经典线程同步 互斥量Mutex

    本文转载于:http://blog.csdn.net/morewindows/article/details/7470936 前面介绍了关键段CS.事件Event在经典线程同步问题中的使用.本篇介绍用 ...

随机推荐

  1. 【CF617D】Roads in Yusland

    [CF617D]Roads in Yusland 题面 蒯的洛谷的 题解 我们现在已经转化好了题目了,戳这里 那么我们考虑怎么求这个东西,我们先判断一下是否所有的边都能被覆盖,不行的话输出\(-1\) ...

  2. 4557: [JLoi2016]侦察守卫

    4557: [JLoi2016]侦察守卫 链接 分析: 因为D比较小,所设状态f[i][j]表示子树i内,从i往下第j层及第j层以下都覆盖了的最小代价,g[i][j]表示覆盖完子树内所有点,还可以往上 ...

  3. Dbzoj#3188. [Coci 2011]Upit

    写道数据结构练练手哈哈哈 // It is made by XZZ #include<cstdio> #include<algorithm> #include<cstdl ...

  4. [Luogu4182][USACO18JAN]Lifeguards P[单调队列]

    题意 给定 \(n\) 个区间,必须去掉其中的 \(K\) 个,询问能够保留的区间并的最大值. \(n \leq 10^5\ ,K \leq 100\) . 分析 定义状态 \(f_{i,j}\) 表 ...

  5. CSS3设置背景图片的大小

    设置背景图片的大小,以长度值或百分比显示,还可以通过cover和contain来对图片进行伸缩. background-size 语法详解: 要在插入图片之后进行设置背景图片的大小 backgroun ...

  6. UWP 应用程序名称本地化以及商店显示名称本地化

    大家应该都知道,在做多语言的时候,我们一般会让App名字也会随着语言变化而本地化. 比如我的App微识别 https://www.microsoft.com/store/productId/9PDSN ...

  7. nodejs 不支持 typescript (...paramName:any[])剩余参数。变相支持方式。

    node es6 变相实现支持ts的剩余参数实现方式 //.ts method assign(to: any, options?: AssignOptions, ...forms: any[]){} ...

  8. log4cpp简单使用及踩到的坑

    log4cpp是log4j的一个扩展, C++开发者可用该库记录日志,可输出到终端,亦可保存到文件. 下面简单demo展示如何输出日志到输出终端. #include <iostream> ...

  9. c++ 整数和字符串的转化

    一.string转int的方式 采用最原始的string, 然后按照十进制的特点进行算术运算得到int,但是这种方式太麻烦,这里不介绍了. 采用标准库中atoi函数. "; int a = ...

  10. easyui panel异步获取后台数据在前台显示

    我在使用easyui的时候,想做一个向下图所示的效果,这个panel的样式已经做好了,想从后台异步获取json数据,然后填入到文本框中,不知道哪位大神能给点指导?万分感谢! 放入表单中,使用form对 ...