C++临界区

(13) 2024-03-17 16:23

Hi,大家好,我是编程小6,很荣幸遇见你,我把这些年在开发过程中遇到的问题或想法写出来,今天说一说C++临界区,希望能够帮助你!!!。

原文链接:C++临界区

一、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;
}

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

3、Linux平台

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

#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、互斥量:为协调共同对一个共享资源的单独访问而设计的。

 

临界区(Critical Section) 保证在某一时刻只有一个线程能访问数据的简便办法。在任意时刻只允许一个线程对共享资源进行访问。如果有多个线程试图同时访问临界区,那么在有一个线 程进入后其他所有试图访问此临界区的线程将被挂起,并一直持续到进入临界区的线程离开。临界区在被释放后,其他线程可以继续抢占,并以此达到用原子方式操 作共享资源的目的。 临界区包含两个操作原语: EnterCriticalSection() 进入临界区 LeaveCriticalSection() 离开临界区 EnterCriticalSection()语句执行后代码将进入临界区以后无论发生什么,必须确保与之匹配的 LeaveCriticalSection()都能够被执行到。否则临界区保护的共享资源将永远不会被释放。虽然临界区同步速度很快,但却只能用来同步本 进程内的线程,而不可用来同步多个进程中的线程。

使用临界区的步骤

1 . 申请一个临界区变量  CRITICAL_SECTION gSection;

2. 初始化临界区  InitializeCriticalSection(&gSection);

3. 使用临界区 EnterCriticalSection(&gSection); ..省略代码..LeaveCriticalSection(&gSection);

4.释放临界区 DeleteCriticalSection(&gSection);

实例代码如下:
--------------------- 
作者:lzg13541043726 
来源:CSDN 
原文:https://blog.csdn.net/lzg13541043726/article/details/37903405 
版权声明:本文为博主原创文章,转载请附上博文链接!

今天的分享到此就结束了,感谢您的阅读,如果确实帮到您,您可以动动手指转发给其他人。

上一篇

已是最后文章

下一篇

已是最新文章

发表回复