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);`

}

windows多线程同步--临界区教程

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

关于临界区的详细解释清参考秒杀多线程第五篇 经典线程同步 关键段CS

【版权声明】转载请注明出处http://www.cnblogs.com/TenosDoIt/p/3601308.html

标签: none

相关文章推荐

添加新评论,含*的栏目为必填