临界区

简介

不论是硬件临界资源,还是软件临界资源,多个进程必须互斥地对它进行访问。每个进程中访问临界资源的那段代码称为临界区(Critical
Section)(临界资源是一次仅允许一个进程使用的共享资源)。每次只准许一个进程进入临界区,进入后不允许其他进程进入。不论是硬件临界资源,还是软件临界资源,多个进程必须互斥地对它进行访问。

多个进程中涉及到同一个临界资源的临界区称为相关临界区。

程序调度法则

进程进入临界区的调度原则是:

1、如果有若干进程要求进入空闲的临界区,一次仅允许一个进程进入。

2、任何时候,处于临界区内的进程不可多于一个。如已有进程进入自己的临界区,则其它所有试图进入临界区的进程必须等待。

3、进入临界区的进程要在有限时间内退出,以便其它进程能及时进入自己的临界区。

4、如果进程不能进入自己的临界区,则应让出CPU,避免进程出现“忙等”现象。

线程同步问题

有多个线程试图同时访问临界区,那么在有一个线程进入后其他所有试图访问此临界区的线程将被挂起,并一直持续到进入临界区的线程离开。临界区在被释放后,其他线程可以继续抢占,并以此达到用原子方式操作共享资源的目的。

临界区在使用时以CRITICAL_SECTION结构对象保护共享资源,并分别用EnterCriticalSection()和LeaveCriticalSection()函数去标识和释放一个临界区。所用到的CRITICAL_SECTION结构对象必须经过InitializeCriticalSection()的初始化后才能使用,而且必须确保所有线程中的任何试图访问此共享资源的代码都处在此临界区的保护之下。否则临界区将不会起到应有的作用,共享资源依然有被破坏的可能。

下面通过一段代码展示了临界区在保护多线程访问的共享资源中的作用。通过两个线程来分别对全局变量g_cArray[10]进行写入操作,用临界区结构对象g_cs来保持线程的同步,并在开启线程前对其进行初始化。为了使实验效果更加明显,体现出临界区的作用,在线程函数对共享资源g_cArray[10]的写入时,以Sleep()函数延迟1毫秒,使其他线程同其抢占CPU的可能性增大。如果不使用临界区对其进行保护,则共享资源数据将被破坏(参见图1(a)所示计算结果),而使用临界区对线程保持同步后则可以得到正确的结果(参见图1(b)所示计算结果)。

代码实现清单附下:


 1 // 临界区结构对象
2 CRITICAL_SECTION g_cs;
3 // 共享资源
4 char g_cArray[10];
5 UINT ThreadProc10(LPVOID pParam)
6 {
7 // 进入临界区
8 EnterCriticalSection(&g_cs);
9 // 对共享资源进行写入操作
10 for (int i = 0; i < 10; i++)
11 {
12 g_cArray[i] = a;
13 Sleep(1);
14 }
15 // 离开临界区
16 LeaveCriticalSection(&g_cs);
17 return 0;
18 }
19 UINT ThreadProc11(LPVOID pParam)
20 {
21 // 进入临界区
22 EnterCriticalSection(&g_cs);
23 // 对共享资源进行写入操作
24 for (int i = 0; i < 10; i++)
25 {
26 g_cArray[10 - i - 1] = b;
27 Sleep(1);
28 }
29 // 离开临界区
30 LeaveCriticalSection(&g_cs);
31 return 0;
32 }
33 ……
34 void CSample08View::OnCriticalSection()
35 {
36 // 初始化临界区
37 InitializeCriticalSection(&g_cs);
38 // 启动线程
39 AfxBeginThread(ThreadProc10, NULL);
40 AfxBeginThread(ThreadProc11, NULL);
41 // 等待计算完毕
42 Sleep(300);
43 // 报告计算结果
44 CString sResult = CString(g_cArray);
45 AfxMessageBox(sResult);
46 }

其他问题


在使用临界区时,一般不允许其运行时间过长,只要进入临界区的线程还没有离开,其他所有试图进入此临界区的线程都会被挂起而进入到等待状态,并会在一定程度上影响程序的运行性能。尤其需要注意的是不要将等待用户输入或是其他一些外界干预的操作包含到临界区。如果进入了临界区却一直没有释放,同样也会引起其他线程的长时间等待。换句话说,在执行了EnterCriticalSection()语句进入临界区后无论发生什么,必须确保与之匹配的LeaveCriticalSection()都能够被执行到。可以通过添加结构化异常处理代码来确保LeaveCriticalSection()语句的执行。虽然临界区同步速度很快,但却只能用来同步本进程内的线程,而不可用来同步多个进程中的线程。

-------------------------------------------------------------------------------------------------

原文链接 http://baike.baidu.com/view/1237110.htm?fr=aladdin

-------------------------------------------------------------------------------------------------

临界区,布布扣,bubuko.com

时间: 2024-10-28 04:24:19

临界区的相关文章

C++拾遗--多线程:临界区解决子线程的互斥

C++拾遗--多线程:临界区解决子线程的互斥 前言 为了解决子线程的互斥问题,windows系统提出了关键段或临界区(CRITICAL_SECTION)的概念.它一共有四个共两对操作:初始化.销毁,进入.离开.它们定义在头文件synchapi.h中. 1.初始化变量 VOID WINAPI InitializeCriticalSection( LPCRITICAL_SECTION lpCriticalSection ); 2.销毁变量 VOID WINAPI DeleteCriticalSect

CriticalSection 临界区

// 临界区.cpp : 定义控制台应用程序的入口点.// #include "stdafx.h"#include<windows.h>#include<iostream>using namespace std; DWORD g_cnt1;DWORD g_cnt2;BOOL g_bContinue = TRUE;CRITICAL_SECTION cs; DWORD WINAPI ThreadProc(__in LPVOID lpParameter){ ::Ent

VC多线程临界区(转)

用于理解CriticalSection. 在使用多线程时,一般很少有多个线程完全独立的工作.往往是多个线程同时操作一个全局变量来获取程序的运行结果.多个线程同时访问同一个全局变量,如果都是读取操作,则不会出现问题.如果是写操作,则会发生错误.这时候,我们可以通过临界区,为全局变量设置一个保护,保证同时只有一个线程可以访问此变量,其他变量进入等待状态.       临界区(Critical Section)是一段独占对某些共享资源访问的代码,在任意时刻只允许一个线程对共享资源进行访问.如果有多个线

线程,临界区的研究

线程是进程的一条执行路径,它包含独立的堆栈和CPU寄存器状态,每个线程共享所有的进程资源,包括打开的文件.信号标识及动态分配的内存等.一个进程内的所有线程使用同一个地址空间,而这些线程的执行由系统调度程序控制,调度程序决定哪个线程可执行以及什么时候执行线程.线程有优先级别,优先权较低的线程必须等到优先权较高的线程执行完后再执行.在多处理器的机器上,调度程序可将多个线程放到不同的处理器上去运行,这样可使处理器任务平衡,并提高系统的运行效率. 多线程编程在Win32方式下和MFC类库支持下的原理是一

临界区与互斥量区别

临界区和互斥锁的区别1.临界区只能用于对象在同一进程里线程间的互斥访问:互斥体可以用于对象进程间或线程间的互斥访问.2.临界区是非内核对象,只在用户态进行锁操作,速度快:互斥体是内核对象,在核心态进行锁操作,速度慢.3.临界区和互斥体在Windows平台都下可用:Linux下只有互斥体可用

临界区、互斥量、事件、信号量四种方式

临界区(Critical Section).互斥量(Mutex).信号量(Semaphore).事件(Event)的区别 1.临界区:通过对多线程的串行化来访问公共资源或一段代码,速度快,适合控制数据访问.在任意时刻只允许一个线程对共享资源进行访问,如果有多个线程试图访问公共资源,那么在有一个线程进入后,其他试图访问公共资源的线程将被挂起,并一直等到进入临界区的线程离开,临界区在被释放后,其他线程才可以抢占. 2.互斥量:采用互斥对象机制. 只有拥有互斥对象的线程才有访问公共资源的权限,因为互斥

线程同步之临界区

临界区:当两个线程竞争同一资源时,如果对资源的访问顺序敏感,就称存在竞态条件.导致竞态条件发生的代码区称作临界区.临界区线程同步适用范围:它只能同步一个进程中的线程,不能跨进程同步.一般用它来做单个进程内的代码快同步,效率比较高. 在.Net中有Monitor.Lock等方式是以临界区的方式来实现线程同步的,我们看一下两者的具体示例. 1.Lock  Lock关键字将代码块标记为临界区,方法是获取指定对象的互斥锁,执行语句,然后释放锁,这样其它线程就可以接着获取锁来进入临界区. Lock关键字保

【转】【Linux】 临界区,互斥量,信号量,事件的区别

原文地址:http://blog.itpub.net/10697500/viewspace-612045/ Linux中 四种进程或线程同步互斥的控制方法1.临界区:通过对多线程的串行化来访问公共资源或一段代码,速度快,适合控制数据访问. 2.互斥量:为协调共同对一个共享资源的单独访问而设计的. 3.信号量:为控制一个具有有限数量用户资源而设计. 4.事 件:用来通知线程有一些事件已发生,从而启动后继任务的开始.     临界区(Critical Section) 保证在某一时刻只有一个线程能访

高级线程同步 临界区

高级线程同步关键代码段1.原子操作.2.临界区指定一个CRITICAL_SECTION 数据结构g_cs,然后对EnterCriticalSection和LeaveCriticalSection访问共享资源当拥有一项可供多个线程访问的资源时,应该创建临界区.类似多个人上厕所.如果多个不是一道线程使用的资源,比如线程1和线程2访问一个资源,线程1和线程3访问另一个资源.那么应该为每个资源创建独立的厕所. 缺点无法对多个进程中的各线程进行同步. 初始化:InitializeCriticalSecti

【Java】利用synchronized(this)完成线程的临界区

在<[Java]线程并发.互斥与同步>(点击打开链接)中利用了操作系统通过操作信号量控制的原始方法,完成了线程的互斥与同步,说句题外话,其实这个信号量的算法,是著名的迪杰斯特拉创造的,也就是数据结构.计算机网络上面最短路径算法.迪杰斯特拉算法.Dijkstra算法的贡献人.其实Java里面根本就不需要自己定义一个信号量来实现临界区,Java对于临界区的实现早已封装好了,而且synchronized还是Java的关键字. 那么,到底怎么来使用这个关键字呢?下面就对上次<[Java]线程并发