一、关键段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. Vue实例 中的常用配置项

    创建Vue实例时,使用 new Vue ({//配置项}) 或者 组件定义中 export default {//配置项},所有的Vue组件都是Vue实例,并且接受相同的选项对象(一些根实例特有的选项 ...

  2. CentOS 下 SonarQube 6.7 的下载、配置、问题排查

    CentOS 下 SonarQube 6.7 的下载.配置.问题排查 系统: CentOS 7 x86_64 SonarQube 版本: 6.7.3 Java 版本: 1.8.0_171 MySQL ...

  3. react-native初体验(2) — 认识路由

    如果学习止步于 hello world, 那么人生也太没意思了.这次要做一个看起来真实的应用.多添加几个页面,让他们可以交互,动起来. react-native 官方推荐使用 react-naviga ...

  4. Python字符串符号:双引号/单引号用法注解。

    众所周知python中单引号和双引号常常被我们所使用,例如print.input等等. 但是对于打印输出所引导的字符串大多都是用双引号的形式来做,"Hello,python!",而 ...

  5. 在python脚本中设置环境变量,并运行相关应用

    1. 问题 在自动化应用的时候 ,有时候环境变量与运行需要不一致.这时候有两种选择: 改变节点环境变量,使得其和运行需求保持一致: 在自动化脚本中设置环境变量,其范围只在脚本运行环境中有效. 显然,当 ...

  6. Hyperledger Fabric CA User’s Guide——开始(三)

    Fabric CA User’s Guide——开始 先决条件 安装Go 1.9+ 设置正确的GOPATH环境变量 安装了libtool和libtdhl-dev包 下面是在Ubuntu上安装libto ...

  7. Calico网络方案

    参考文档: Difficulties with traditional overlay networks:https://www.projectcalico.org/learn/ Get Start( ...

  8. 深度学习-tensorflow学习笔记(1)-MNIST手写字体识别预备知识

    深度学习-tensorflow学习笔记(1)-MNIST手写字体识别预备知识 在tf第一个例子的时候需要很多预备知识. tf基本知识 香农熵 交叉熵代价函数cross-entropy 卷积神经网络 s ...

  9. nodejs 中jead模板改为ejs

    var app = express(); // view engine setup app.set('views', path.join(__dirname, 'views')); app.set(' ...

  10. maven实战读书笔记(一)

    环境变量设置 MAVEN_HOME:G:\maven-3.2\apache-maven-3.2.5 Path: G:\maven-3.2\apache-maven-3.2.5\bin 其实正确的设置应 ...