windows多线程同步--临界区教程
windows多线程同步--临界区
推荐参考博客:秒杀多线程第五篇 经典线程同步 关键段CS
关于临界区的观念,一般操作系统书上面都有。
适用范围:它只能同步一个进程中的线程,不能跨进程同步。一般用它来做单个进程内的代码快同步,效率比较高
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
`#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
`#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);`
}
为什么会这样呢,因为临界区有所有权的概念,即某个线程进入临界区后,就拥有该临界区的所有权,在他离开临界区之前,他可以无限次的再次进入该临界区,上例中线程A获得临界区1的所有权后,在线程C调用LeaveCriticalSection(&g\_cs1)之前,A是可以无限次的进入临界区1的。利用信号量之所以可以实现题目的要求,是因为信号量没有所有权的概念,某个线程获得信号量后,如果信号量的值为0,那么他一定要等到信号量被释放时,才能再次获得
关于临界区的详细解释清参考秒杀多线程第五篇 经典线程同步 关键段CS
【版权声明】转载请注明出处:http://www.cnblogs.com/TenosDoIt/p/3601308.html