windows多线程(四) 关键段 CriticalSection
一、问题回顾
我们上一篇文章最后的程序的输出 g_Count 的值不是每次都正确,原因是没有对全局资源 g_Count 进行互斥访问(就是同一时刻只能由一个线程访问),接下来我们就来说一下使用关键段来给全局资源加锁以实现互斥访问。
这是上一篇中的程序:
#include <stdio.h>
#include <windows.h>
const unsigned int THREAD_NUM = 50;
unsigned int g_Count = 0;
DWORD WINAPI ThreadFunc(LPVOID);
int main()
{
HANDLE hThread[THREAD_NUM];
for (int i = 0; i < THREAD_NUM; i++)
{
hThread[i] = CreateThread(NULL, 0, ThreadFunc, 0, 0, NULL); // 创建线程
}
WaitForMultipleObjects(THREAD_NUM, hThread, true, INFINITE); //一直等待,直到所有子线程全部返回
printf(" 总共 %d 个线程给 g_Count 的值加一,现在 g_Count = %d\n", THREAD_NUM, g_Count);
return 0;
}
DWORD WINAPI ThreadFunc(LPVOID p)
{
Sleep(50);
g_Count++;
Sleep(50);
return 0;
}
二、 关键段 CriticalSection 声明及相关函数
(一)CriticalSection 声明
CRITICAL_SECTION 关键段名字; // eg: CRITICAL_SECTION cs;
CRITICAL_SECTION 结构说明:在 vs 中 先声明一个 关键段, 鼠标放到 CRITICAL_SECTION 关键字上按 F12 转到定义如下:
typedef RTL_CRITICAL_SECTION CRITICAL_SECTION;
再把鼠标放到 RTL_CRITICAL_SECTION 上按 F12 即可转到 CRITICAL_SECTION 结构体的定义 如下:
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; 旋转锁的设置,用于多处理器。
(二)CriticalSection相关函数
1.函数功能:初始化,定义关键段变量后必须先初始化。
void InitializeCriticalSection(LPCRITICAL_SECTIONlpCriticalSection);
2.函数功能:销毁,用完之后记得销毁。
void DeleteCriticalSection(LPCRITICAL_SECTIONlpCriticalSection);
3.函数功能:进入关键区域,系统保证各线程互斥的进入关键区域。
void EnterCriticalSection(LPCRITICAL_SECTIONlpCriticalSection);
4.函数功能:离开关关键区域
void LeaveCriticalSection(LPCRITICAL_SECTIONlpCriticalSection);
三、实例
现在使用关键段来解决上面的问题,代码如下:
#include <stdio.h>
#include <windows.h>
const unsigned int THREAD_NUM = 50;
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++)
{
hThread[i] = CreateThread(NULL, 0, ThreadFunc, 0, 0, NULL); // 创建线程
}
WaitForMultipleObjects(THREAD_NUM, hThread, true, INFINITE); //一直等待,直到所有子线程全部返回
printf(" 总共 %d 个线程给 g_Count 的值加一,现在 g_Count = %d\n", THREAD_NUM, g_Count);
DeleteCriticalSection(&cs); //销毁关键段
return 0;
}
DWORD WINAPI ThreadFunc(LPVOID p)
{
Sleep(50);
EnterCriticalSection(&cs); // 进入关键段
g_Count++;
LeaveCriticalSection(&cs); // 离开关键段
Sleep(50);
return 0;
}
运行结果如下图所示,给全局资源 g_Count 加锁,实现互斥访问,就能够让每个线程正确给 g_Count 值加一 :

windows多线程(四) 关键段 CriticalSection的更多相关文章
- Windows多线程中关键段(Critical Section)的应用
先看如下代码:(用Visual Studio 2010按照Win32 Console程序创建向导创建) #include "stdafx.h" #include <proce ...
- windows多线程(六) 互斥量Mutex与关键段CriticalSection比较
一.关键段CS 和 互斥量Mutex 的相同点:都有线程拥有权 关键段和互斥量都有线程拥有权,即可以被一个线程拥有.在 前面讲关键段CS的文章中有说到,关键段结构体的第四个参数保存着拥有该关键段的线程 ...
- windows多线程(八) 信号量Semaphore
如果你看到了这里,我就认为你已经对掌握了有关关键段 CriticalSection.互斥量Mutex和事件Event有关的内容,所以最基本的东西就不再介绍了.如果没有掌握上面说的内容,可以看这里: 关 ...
- windows多线程(七) 事件event
前面说的互斥量Mutex与关键段CriticalSection都不能实现线程的同步,只能实现互斥,接下来我们用时间event就可以实现线程的同步了,事件也是一个内核对象. 一.相关函数说明 (一) 创 ...
- [一个经典的多线程同步问题]解决方案一:关键段CS
前面提出了一个经典的多线程同步互斥问题,本篇将用关键段CRITICAL_SECTION来尝试解决这个问题. 本文先介绍如何使用关键段,然后再深层次的分析下关键段的实现机制和原理. 关键段CRITICA ...
- 多线程面试题系列(5):经典线程同步 关键段CS
上一篇提出了一个经典的多线程同步互斥问题,本篇将用关键段CRITICAL_SECTION来尝试解决这个问题.本文首先介绍下如何使用关键段,然后再深层次的分析下关键段的实现机制与原理.关键段CRITIC ...
- 秒杀多线程第五篇 经典线程同步 关键段CS
本文首先介绍下如何使用关键段,然后再深层次的分析下关键段的实现机制与原理. 关键段CRITICAL_SECTION一共就四个函数,使用很是方便.下面是这四个函数的原型和使用说明. 函数功能:初始化 函 ...
- 转---秒杀多线程第五篇 经典线程同步 关键段CS
上一篇<秒杀多线程第四篇 一个经典的多线程同步问题>提出了一个经典的多线程同步互斥问题,本篇将用关键段CRITICAL_SECTION来尝试解决这个问题. 本文首先介绍下如何使用关键段,然 ...
- windows多线程编程星球(一)
以前在学校的时候,多线程这一部分是属于那种充满好奇但是又感觉很难掌握的部分.原因嘛我觉得是这玩意儿和编程语言无关,主要和操作系统的有关,所以这部分内容主要出现在讲原理的操作系统书的某一章,看完原理是懂 ...
随机推荐
- 将windows上.net core 发布的程序部署到linux(ubantu等)上
首先在linux安装相应的.net core 环境,根据官方的示例安装即可:参考地址:https://dotnet.microsoft.com/learn/dotnet/hello-world-tut ...
- restful framework之权限组件
一.权限简介 只用超级用户才能访问指定的数据,普通用户不能访问,所以就要有权限组件对其限制 二.局部使用 from rest_framework.permissions import BasePerm ...
- JS字符串补全方法padStart()和padEnd()
背景: var t = new Date().getMonth() + 1; // t ===> 7,没有0,怎么展示成下面的样子? // 2018-07-23 解决上述问题的一个思路: // ...
- JTree实现电脑资源管理器
0.前言 最近老师布置了一项用Java写资源管理器的任务,一开始以为简单,但是实际操作起来,却发现网上的资源用起来相对生疏.在使用中,我也遇到了许多问题,虽然不能像其他博主一样,写的非常齐全,但我还是 ...
- shell 本地接口自动化
一.基于http/https的接口 一般情况下,当前大多公司在做接口自动化的时候都会使用一些工具:比如:postman/jmeter/python自研开发接口平台... 以上的情况,都是在源码与测试使 ...
- flask中的宏
对于flask中的宏编程.我们使用 macro 来对宏起个名称 宏编程 对于我们来说是减少了代码的重用.以及简化了标签的操作,对与开发效率有很大的提升, 在html中.相信大多数都用到了.input ...
- 木马分析出现python语言,360的安全人员不禁感叹还有这种操作?
几年前,敲诈者木马还是一个默默无闻的木马种类.然而,由于其极强的破坏力和直接且丰厚的财富回报,敲诈者木马这几年已经一跃成为曝光率最高的木马类型——甚至超越了盗号木马.远控木马.网购木马这传统三强.与此 ...
- JavaScript学习笔记(八)—— 补
第九章 最后的补充 一.Jquery简单阐述 JQuery是一个JavaScript库,旨在减少和简化处理DOM和添加视觉效果的JavaScript代码:使用时必须得添加库路径:学习路径:http:/ ...
- sqlmap 进阶 (一)
0x1 命令 以此类推,可以具体自己研究有哪些参数,放在哪,有什么用,怎么用 参考:https://blog.csdn.net/bo_mask/article/details/76130848 0x2 ...
- virtualbox命令行启动虚拟机和关闭虚拟机
C:\Program Files\Oracle\VirtualBox\VBoxManage.exe startvm 虚拟机名字 --type headlessC:\Program Files\Orac ...