windows多线程同步--临界区

简介:

关于临界区的观念,一般操作系统书上面都有。

适用范围:它只能同步一个进程中的线程,不能跨进程同步。一般用它来做单个进程内的代码快同步,效率比较高

windows中与临界区有关的结构是 CRITICAL_SECTION,关于该结构体的内部结构可参考here

使用时,主线程中要先初始化临界区,最后要删除临界区,具体使用见下面代码:

                                                                              本文地址

从一个例子来说明:假设有三个线程都需要使用打印机,我们可以把打印的代码放到临界区,这样就可以保证每次只有一个线程在使用打印机。

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include<string>
  #include<iostream>
  #include<process.h>
  #include<windows.h>
  using  namespace  std;
 
  //定义一个临界区
  CRITICAL_SECTION g_cs;
 
//线程绑定的函数返回值和参数是确定的,而且一定要__stdcall
unsigned __stdcall threadFun( void  *param)
{
     EnterCriticalSection(&g_cs); //进入临界区,如果有其他线程则等待
     cout<<*(string *)(param)<<endl;
     LeaveCriticalSection(&g_cs); //退出临界区,其他线程可以进来了
     return  1;
}
 
 
int  main()
{
     //初始化临界区
     InitializeCriticalSection(&g_cs);
 
     HANDLE  hth1, hth2, hth3;
     string s1 = "first" , s2 = "second" , s3 = "third" ;
 
     //创建线程
     hth1 = ( HANDLE )_beginthreadex(NULL, 0, threadFun, &s1, 0, NULL);
     hth2 = ( HANDLE )_beginthreadex(NULL, 0, threadFun, &s2, 0, NULL);
     hth3 = ( HANDLE )_beginthreadex(NULL, 0, threadFun, &s3, 0, NULL);
 
     //等待子线程结束
     WaitForSingleObject(hth1, INFINITE);
     WaitForSingleObject(hth2, INFINITE);
     WaitForSingleObject(hth3, INFINITE);
 
     //一定要记得关闭线程句柄
     CloseHandle(hth1);
     CloseHandle(hth2);
     CloseHandle(hth3);
 
     //删除临界区
     DeleteCriticalSection(&g_cs);
}

 

再看另外一个问题:编写一个程序,开启3个线程,这3个线程的ID分别为A、B、C,每个线程将自己的ID在屏幕上打印10遍,要求输出结果必须按ABC的顺序显示;如:ABCABC….依次递推, 仿照文章windows多线程同步--信号量中的代码,我们把信号量替换成临界区。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#include<string>
  #include<iostream>
  #include<process.h>
  #include<windows.h>
  using  namespace  std;
  //声明3个临界区
CRITICAL_SECTION  g_cs1, g_cs2, g_cs3;
 
//线程绑定的函数返回值和参数是确定的,而且一定要__stdcall
unsigned __stdcall threadFunA( void  *)
{
     for ( int  i = 0; i < 10; i++){
         EnterCriticalSection(&g_cs1); //进入临界区
         cout<< "A" ;
         LeaveCriticalSection(&g_cs2); //离开临界区
     }
     return  1;
}
unsigned __stdcall threadFunB( void  *)
{
     for ( int  i = 0; i < 10; i++){
         EnterCriticalSection(&g_cs2); //进入临界区
         cout<< "B" ;
         LeaveCriticalSection(&g_cs3); //离开临界区
     }
     return  2;
}
unsigned __stdcall threadFunC( void  *)
{
     for ( int  i = 0; i < 10; i++){
         EnterCriticalSection(&g_cs3); //进入临界区
         cout<< "C" ;
         LeaveCriticalSection(&g_cs1); //离开临界区
     }
     return  3;
}
 
 
int  main()
{
     //初始化临界区
     InitializeCriticalSection(&g_cs1);
     InitializeCriticalSection(&g_cs2);
     InitializeCriticalSection(&g_cs3);
 
     HANDLE  hth1, hth2, hth3;
 
     //创建线程
     hth1 = ( HANDLE )_beginthreadex(NULL, 0, threadFunA, NULL, 0, NULL);
     hth2 = ( HANDLE )_beginthreadex(NULL, 0, threadFunB, NULL, 0, NULL);
     hth3 = ( HANDLE )_beginthreadex(NULL, 0, threadFunC, NULL, 0, NULL);
 
     //等待子线程结束
     WaitForSingleObject(hth1, INFINITE);
     WaitForSingleObject(hth2, INFINITE);
     WaitForSingleObject(hth3, INFINITE);
 
     //一定要记得关闭线程句柄
     CloseHandle(hth1);
     CloseHandle(hth2);
     CloseHandle(hth3);
 
     //删除临界区
     DeleteCriticalSection(&g_cs1);
     DeleteCriticalSection(&g_cs2);
     DeleteCriticalSection(&g_cs3);
}

 

image

为什么会这样呢,因为临界区有所有权的概念,即某个线程进入临界区后,就拥有该临界区的所有权,在他离开临界区之前,他可以无限次的再次进入该临界区,上例中线程A获得临界区1的所有权后,在线程C调用LeaveCriticalSection(&g_cs1)之前,A是可以无限次的进入临界区1的。利用信号量之所以可以实现题目的要求,是因为信号量没有所有权的概念,某个线程获得信号量后,如果信号量的值为0,那么他一定要等到信号量被释放时,才能再次获得






本文转自tenos博客园博客,原文链接:http://www.cnblogs.com/TenosDoIt/p/3601308.html,如需转载请自行联系原作者

目录
相关文章
|
1天前
|
Java 云计算
Java多线程编程中的同步与互斥机制探析
在当今软件开发领域,多线程编程是一项至关重要的技能。本文将深入探讨Java中的同步与互斥机制,分析其在多线程环境下的应用及实现原理,帮助读者更好地理解并运用这一关键技术。
27 4
|
1天前
|
Python
在Python中,如何保证多个线程之间的同步?
在Python中,如何保证多个线程之间的同步?
26 4
|
1天前
|
Python
如何在Python中实现线程之间的同步和通信?
【2月更文挑战第17天】【2月更文挑战第51篇】如何在Python中实现线程之间的同步和通信?
|
1天前
|
算法 调度 索引
什么是多任务和线程?用线程写的一个udp同步聊天器
什么是多任务和线程?用线程写的一个udp同步聊天器
30 0
|
1天前
|
存储 设计模式 安全
Java 编程问题:十、并发-线程池、可调用对象和同步器2
Java 编程问题:十、并发-线程池、可调用对象和同步器
35 0
|
1天前
|
安全 C++
C++多线程编程:并发与同步
C++多线程编程:并发与同步
10 0
|
1天前
|
监控 安全 Java
一文讲明白Java中线程与进程、并发与并行、同步与异步
一文讲明白Java中线程与进程、并发与并行、同步与异步
8 1
|
1天前
|
安全 算法 Java
Java中的多线程并发控制与同步机制
【4月更文挑战第17天】 在现代软件开发中,Java作为一种广泛使用的编程语言,其对多线程的支持是构建高性能应用程序的关键。本文将深入探讨Java中的多线程并发控制与同步机制,包括基本的线程创建、生命周期管理,以及高级的并发工具如synchronized关键字、ReentrantLock类、并发集合和原子变量等。通过理论分析与实例演示,旨在为读者提供一个清晰的多线程并发控制与同步的实现框架,并指出在实践中如何避免常见的并发问题,如死锁、竞态条件和资源争用等。
|
1天前
|
安全 Java 开发者
Java中的多线程并发控制与同步机制
【4月更文挑战第17天】在Java编程中,多线程是实现并行处理和提高程序性能的重要手段。然而,随之而来的线程安全问题和数据一致性问题不容忽视。本文深入剖析了Java中多线程的并发控制与同步机制,包括synchronized关键字、显式锁Lock以及并发集合等高级特性。通过对比分析这些机制的原理和使用场景,旨在帮助开发者理解并合理运用于实际项目中,以解决并发环境下的数据竞争和资源冲突问题。