zoukankan      html  css  js  c++  java
  • C++ 多线程同步之临界区(CriticalSection)

    一、Win32平台

    1、相关头文件和接口

    1 #include <windows.h>
    2 
    3 CRITICAL_SECTION cs;//定义临界区对象
    4 InitializeCriticalSection(&cs);//初始化临界区
    5 EnterCriticalSection(&cs);//进入临界区
    6 LeaveCriticalSection(&cs);//离开临界区
    7 DeleteCriticalSection(&cs);//删除临界区

    2、Win32源码

     1 //=====================MyCriticalSection.h===========================
     2 #ifndef _My_CRITICAL_SECTION_H
     3 #define _My_CRITICAL_SECTION_H
     4 
     5 #include <windows.h>
     6 //对临界区同样进行封装
     7 class CMyCriticalSection
     8 {
     9 public:
    10     CMyCriticalSection()
    11     {
    12         InitializeCriticalSection(&m_cSection);
    13     }
    14 
    15     void Lock()
    16     {
    17         EnterCriticalSection(&m_cSection);
    18     }
    19 
    20     void UnLock()
    21     {
    22         LeaveCriticalSection(&m_cSection);
    23     }
    24 
    25 
    26     //利用析构函数删除临界区对象
    27     virtual ~CMyCriticalSection()
    28     {
    29         DeleteCriticalSection(&m_cSection);
    30     }
    31 private:
    32     CRITICAL_SECTION                        m_cSection;
    33 };
    34 
    35 class CCriticalSectionAutoLock
    36 {
    37 public:
    38     //利用构造函数上锁,即进去临界区
    39     CCriticalSectionAutoLock(CMyCriticalSection *mySection)
    40     :pCMySection(mySection)
    41     {
    42         pCMySection->Lock();
    43     }
    44 
    45     //利用析构函数解锁,即离开临界区
    46     virtual ~CCriticalSectionAutoLock()
    47     {
    48         pCMySection->UnLock();
    49     }
    50 private:
    51     CMyCriticalSection                      *pCMySection;
    52 };
    53 
    54 #endif
     1 #include <iostream>
     2 #include <windows.h>
     3 #include "MySemaphore.h"
     4 #include "MyMutex.h"
     5 #include "MyCriticalSection.h"
     6 using namespace std;
     7 
     8 //HANDLE g_hSemaphore = NULL;
     9 //HANDLE g_hMutex = NULL;
    10 
    11 CMySemaphore                    MySemaphore;            //信号量
    12 CMyMutex                        MyMutex;                //互斥量
    13 CMyCriticalSection              MyCriticalSection;      //临界区
    14 
    15 DWORD WINAPI Fun(LPVOID lpParamter)
    16 {
    17     string strPrint((const char*)lpParamter);
    18     int iRunTime = 0;
    19     //执行100次跳出
    20     while(++iRunTime<10)
    21     {
    22         {
    23             CCriticalSectionAutoLock  cLock(&MyCriticalSection);
    24             cout <<"["<< iRunTime <<"]:"<< strPrint.c_str()<<endl;
    25         }
    26         Sleep(1); //若去掉此句 可能导致其他线程无法进入临界区,因为 cLock在这之前析构,离开临界区
    27 
    28     }
    29     return 0;
    30 }
    31 
    32 int main()
    33 {
    34     //创建五个子线程
    35     string str1 = "A";
    36     string str2 = "B";
    37     string str3 = "C";
    38     string str4 = "D";
    39     string str5 = "E";
    40 
    41     HANDLE hThread1 = CreateThread(NULL, 0, Fun, (void*)str1.c_str(), 0, NULL);
    42     HANDLE hThread2 = CreateThread(NULL, 0, Fun, (void*)str2.c_str(), 0, NULL);
    43     HANDLE hThread3 = CreateThread(NULL, 0, Fun, (void*)str3.c_str(), 0, NULL);
    44     HANDLE hThread4 = CreateThread(NULL, 0, Fun, (void*)str4.c_str(), 0, NULL);
    45     HANDLE hThread5 = CreateThread(NULL, 0, Fun, (void*)str5.c_str(), 0, NULL);
    46 
    47     //关闭线程
    48     CloseHandle(hThread1);
    49     CloseHandle(hThread2);
    50     CloseHandle(hThread3);
    51     CloseHandle(hThread4);
    52     CloseHandle(hThread5);
    53 
    54     getchar();
    55 //  system("pause");
    56     return 0;
    57 }

    执行结果:
    这是加上Sleep(1);的运行结果,没有加上Sleep(1);的执行结果如下:

    从结果我们可以看出如果没有加上Sleep(1),即在离开临界区后进行休眠,其他线程进入临界区的概率会大大降低,原因可能是由于While循环在不停的循环时,其他线程还没有那么快能够进入临界区,因此在这种情况下想让所有的线程都有机会进入临界区,则需要在离开临界区之后做短暂休眠即可。

    3、Linux平台
    在Linux环境下,没有Windows下的临界区的概念,但是也可以利用互斥量实现该功能。Linux下的API如下,在前面的博文里也有讲到过

    1 #include <pthread.h>
    2 int pthread_mutexattr_init(pthread_mutexattr_t *attr); /*初始化函数*/
    3 int pthread_mutexattr_destroy(pthread_mutexattr_t *attr);/*去初始化函数*/
    4 
    5 int pthread_mutex_lock(pthread_mutexattr_t *attr)/*加锁*/
    6 int pthread_mutex_unlock(pthread_mutexattr_t *attr)/*解锁*/

    但是两者并不是完全一样的,他们的区别总结如下:
    1、临界区只能用于对象在同一进程里线程间的互斥访问;互斥体可以用于对象进程间或线程间的互斥访问。
    2、临界区是非内核对象,只在用户态进行锁操作,速度快;互斥体是内核对象,在核心态进行锁操作,速度慢。
    3、临界区和互斥体在Windows平台都下可用;Linux下只有互斥体可用。
    4、临界区:通过对多线程的串行化来访问公共资源或一段代码,速度快,适合控制数据访问。
    5、互斥量:为协调共同对一个共享资源的单独访问而设计的。

  • 相关阅读:
    PHP二维数组排序(感谢滔哥lvtao.net)
    MySQL 日志的类型
    PHP安装Xdebug扩展并配置PHPstorm调试(Centos、Windows)
    $.post 和 $.get 设置同步和异步请求
    Jquery获取敲击回车时光标所在的位置
    Jquery 数组与字符串之间的转换
    使整个页面变灰的css代码
    PHP的性能优化方法总结
    Android中完全退出当前应用系统
    Android 遮罩层效果
  • 原文地址:https://www.cnblogs.com/ybqjymy/p/15320059.html
Copyright © 2011-2022 走看看