• C++多线程同步之临界区(CriticalSection)


    原文链接:http://blog.csdn.net/olansefengye1/article/details/53262917

    一、Win32平台

    1、相关头文件和接口

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

    2、Win32源码

    //=====================MyCriticalSection.h===========================
    #ifndef _My_CRITICAL_SECTION_H
    #define _My_CRITICAL_SECTION_H
    
    #include <windows.h>
    //对临界区同样进行封装
    class CMyCriticalSection
    {
    public:
        CMyCriticalSection()
        {
            InitializeCriticalSection(&m_cSection);
        }
    
        void Lock()
        {
            EnterCriticalSection(&m_cSection);
        }
    
        void UnLock()
        {
            LeaveCriticalSection(&m_cSection);
        }
    
    
        //利用析构函数删除临界区对象
        virtual ~CMyCriticalSection()
        {
            DeleteCriticalSection(&m_cSection);
        }
    private:
        CRITICAL_SECTION                        m_cSection;
    };
    
    class CCriticalSectionAutoLock
    {
    public:
        //利用构造函数上锁,即进去临界区
        CCriticalSectionAutoLock(CMyCriticalSection *mySection)
        :pCMySection(mySection)
        {
            pCMySection->Lock();
        }
    
        //利用析构函数解锁,即离开临界区
        virtual ~CCriticalSectionAutoLock()
        {
            pCMySection->UnLock();
        }
    private:
        CMyCriticalSection                      *pCMySection;
    };
    
    #endif
    #include <iostream>
    #include <windows.h>
    #include "MySemaphore.h"
    #include "MyMutex.h"
    #include "MyCriticalSection.h"
    using namespace std;
    
    //HANDLE g_hSemaphore = NULL;
    //HANDLE g_hMutex = NULL;
    
    CMySemaphore                    MySemaphore;            //信号量
    CMyMutex                        MyMutex;                //互斥量
    CMyCriticalSection              MyCriticalSection;      //临界区
    
    DWORD WINAPI Fun(LPVOID lpParamter)
    {
        string strPrint((const char*)lpParamter);
        int iRunTime = 0;
        //执行100次跳出
        while(++iRunTime<10)
        {
            {
                CCriticalSectionAutoLock  cLock(&MyCriticalSection);
                cout <<"["<< iRunTime <<"]:"<< strPrint.c_str()<<endl;
            }
            Sleep(1); //若去掉此句 可能导致其他线程无法进入临界区,因为 cLock在这之前析构,离开临界区
    
        }
        return 0;
    }
    
    int main()
    {
        //创建五个子线程
        string str1 = "A";
        string str2 = "B";
        string str3 = "C";
        string str4 = "D";
        string str5 = "E";
    
        HANDLE hThread1 = CreateThread(NULL, 0, Fun, (void*)str1.c_str(), 0, NULL);
        HANDLE hThread2 = CreateThread(NULL, 0, Fun, (void*)str2.c_str(), 0, NULL);
        HANDLE hThread3 = CreateThread(NULL, 0, Fun, (void*)str3.c_str(), 0, NULL);
        HANDLE hThread4 = CreateThread(NULL, 0, Fun, (void*)str4.c_str(), 0, NULL);
        HANDLE hThread5 = CreateThread(NULL, 0, Fun, (void*)str5.c_str(), 0, NULL);
    
        //关闭线程
        CloseHandle(hThread1);
        CloseHandle(hThread2);
        CloseHandle(hThread3);
        CloseHandle(hThread4);
        CloseHandle(hThread5);
    
        getchar();
    //  system("pause");
        return 0;
    }

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

    3、Linux平台

    在Linux环境下,没有Windows下的临界区的概念,但是也可以利用互斥量实现该功能。Linux下的API如下,在前面的博文里也有讲到过,可以参考http://blog.csdn.net/olansefengye1/article/details/53086141

    include <pthread.h>
    int pthread_mutexattr_init(pthread_mutexattr_t *attr); /*初始化函数*/
    int pthread_mutexattr_destroy(pthread_mutexattr_t *attr);/*去初始化函数*/
    
    int pthread_mutex_lock(pthread_mutexattr_t *attr)/*加锁*/
    int pthread_mutex_unlock(pthread_mutexattr_t *attr)/*解锁*/

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

  • 相关阅读:
    Kotlin协程第一个示例剖析及Kotlin线程使用技巧
    大数据JavaWeb之java基础巩固----Junit&反射&注解
    Kotlin协程重要概念详解【纯理论】
    Kotlin反射在属性上的应用实战
    Kotlin反射操纵构造方法与伴生对象
    个人任务day4
    典型用户和用户场景
    个人任务Day3
    个人任务2
    个人任务1
  • 原文地址:https://www.cnblogs.com/lenmom/p/8017413.html
Copyright © 2020-2023  润新知