C++多线程 互斥锁 信号量 事件 临界区

来源:互联网 发布:java zip打包下载 编辑:程序博客网 时间:2024/05/22 04:35

一、互斥锁

1、先熟悉熟悉API

1,创建互斥锁,并反正一个句柄HANDLE CreateMutex(LPSECURITY_ATTRIBUTESlpMutexAttributes, // 指向安全属性的指针BOOLbInitialOwner, // 初始化互斥对象的所有者,一般设置为FALSELPCTSTRlpName // 互斥对象名);2,释放互斥对象的控制权BOOL ReleaseMutex(HANDLE hMutex //已创建Mutex的句柄);3,打开互斥锁,返回句柄HANDLE OpenMutex(DWORDdwDesiredAccess, // 互斥体的访问权限BOOLbInheritHandle, //如希望子进程能够继承句柄,则为TRUELPCTSTRlpName // 互斥锁名字);4,等待目标返回DWORD WaitForSingleObject(HANDLE hHandle, //目标句柄DWORD dwMilliseconds //等待时间 ,毫秒记,INFINITE为永久等待);

一个简单的互斥锁例子来实现多线程同步

#include<Windows.h>#include<stdlib.h>#include<iostream>using namespace std;static int g_count = 100;class Lock{public:    Lock(char*szName)    {        hd = OpenMutex(MUTEX_ALL_ACCESS, NULL, (LPCWSTR)szName);        WaitForSingleObject(hd, INFINITE);        Sleep(1500);//测试用:等待1.5秒,正式类中不应有    }    ~Lock()    {        ReleaseMutex(hd);    }    static bool InitLock(char*szName)    {        if (!OpenMutex(MUTEX_ALL_ACCESS, NULL, (LPCWSTR)szName))        {            if (!CreateMutex(NULL, NULL, (LPCWSTR)szName))                return false;            return true;        }        return false;    }    HANDLE hd;};UINT address1(LPVOID lparam){    while (1)    {        Lock lc("_temp_lock");        cout << g_count-- << "---" << "address1" << endl;    }}UINT address2(LPVOID lparam){    while (1)    {        Lock lc("_temp_lock");        cout << g_count-- << "---" << "address2" << endl;    }}int main(int argc, char*argv[]){    if(!Lock::InitLock("_temp_lock"))//创建互斥锁失败        return -1;    CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)address1, NULL, NULL, NULL);//开启线程1    CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)address2, NULL, NULL, NULL);//开启线程2    system("pause");    return 0;}

原理浅析:Lock::InitLock()来创建互斥锁,在本demo中,同步是按照CreateThread的创建顺序。创建了一个Lock类,当生成对象的时候就等待,一旦当互斥锁没有控制权,等待即结束,便向下执行,对象析构的时候就释放控制权,以此类推循环。
ps:mutex作用范围在系统层,使用mutex效率并不是太高,使用临界区(作用范围在进程)效率比较高



二、信号量

1,先熟悉熟悉API

CreateSemaphore() 创建一个信号量  OpenSemaphore() 打开一个信号量  ReleaseSemaphore() 释放信号量 WaitForSingleObject() 等待信号量  

2,举个简单的小例子

#include <stdio.h>  #include <Windows.h>  #define THREAD_NUM 20#define SEM_NAME "THREAD_SEMAPHORE"HANDLE g_hSem = NULL;HANDLE g_hThread[THREAD_NUM];void WINAPI ThreadFun(void* param){    printf("进入线程: %u,并等待\n", GetCurrentThreadId());    WaitForSingleObject(g_hSem, INFINITE);    printf("线程: %u 获得信号量\n", GetCurrentThreadId());    long dwSem = 0;    if (!ReleaseSemaphore(g_hSem, 1, &dwSem))        return;    printf("目前资源数:%u\n", dwSem);}int  main(int argc, char*argv[]){    g_hSem = CreateSemaphoreA(NULL, 0, 5, SEM_NAME);    g_hSem = OpenSemaphoreA(SEMAPHORE_MODIFY_STATE, FALSE, SEM_NAME);    for (int i = 0; i < THREAD_NUM; ++i)    {        DWORD dwThreadID = 0;        g_hThread[i] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadFun, NULL, 0, &dwThreadID);    }    WaitForMultipleObjects(THREAD_NUM, g_hThread, TRUE, INFINITE);    printf("全部执行完了\n");    return 0;}

ps:信号量可以说在平常的使用中用的比较少,一般的用途在控制并发线程数量,抢占资源问题。



三、事件

1,先熟悉熟悉API

HANDLE CreateEvent( //创建事件LPSECURITY_ATTRIBUTES lpEventAttributes,// 安全属性BOOL bManualReset,// 复位方式BOOL bInitialState,// 初始状态LPCTSTR lpName // 对象名称);HANDLE OpenEvent( //打开事件DWORD dwDesiredAccess,BOOL bInheritHandle,LPCTSTR lpName);BOOL ResetEvent(//事件对象设置为无信号状态。HANDLE hEvent);BOOL SetEvent(HANDLE hEvent);//事件对象设置为有信号状态。 BOOL PulseEvent(HANDLE hEvent)//事件对象设置为有信号状态,脉冲一个事件WaitForSingleObject() 等待信号量  

2,举个简单的小例子

#include <stdio.h>#include <Windows.h>HANDLE g_hEvent;UINT address1(LPVOID lparam){    printf("进入线程了,等待5秒\n");    WaitForSingleObject(g_hEvent, INFINITE);    printf("等待结束了,向下执行了!\n");    return 0;}UINT address2(LPVOID lparam){    Sleep(5000);    SetEvent(g_hEvent);    return 0;}int main(int argc, char*argv[]){    g_hEvent=CreateEvent(NULL, true, FALSE, NULL);    ResetEvent(g_hEvent);    CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)address1, NULL, NULL, NULL);//开启线程1    CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)address2, NULL, NULL, NULL);//开启线程2    system("pause");    return 0;}

ps:本小例模拟了的两个线程间的同步,address2来控制address1的执行,事件在多线程程序中的应用比较多,比较重要,定要熟练掌握。



四、临界区

1,先熟悉熟悉API

void InitializeCriticalSection(//初始化临界区 LPCRITICAL_SECTION lpCriticalSection); void WINAPI DeleteCriticalSection( //删除临界区  _Inout_ LPCRITICAL_SECTION lpCriticalSection);VOID WINAPI EnterCriticalSection( //进入临界区      __inout LPCRITICAL_SECTION lpCriticalSection); VOID WINAPI LeaveCriticalSection(//离开临界区    _Inout_ LPCRITICAL_SECTION lpCriticalSection    );

2,举个简单的小例子

#include <stdio.h>#include <Windows.h>CRITICAL_SECTION g_cs;int g_nIndex = 20;UINT address1(LPVOID lparam){    while(true)    {        if (10 == g_nIndex)            return 1;        EnterCriticalSection(&g_cs);        printf("address111线程,index=%d\n",g_nIndex);        g_nIndex--;        LeaveCriticalSection(&g_cs);    }    return 0;}UINT address2(LPVOID lparam){    while (true)    {        if (0 == g_nIndex)            return 1;        EnterCriticalSection(&g_cs);        printf("address222线程,index=%d\n", g_nIndex);        --g_nIndex;        LeaveCriticalSection(&g_cs);    }    return 0;}int main(int argc, char*argv[]){    InitializeCriticalSection(&g_cs);    CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)address1, NULL, NULL, NULL);//开启线程1    CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)address2, NULL, NULL, NULL);//开启线程2    system("pause");    DeleteCriticalSection(&g_cs);    return 0;}

ps:小例中,address1被临界区一直占用到到address1退出,address2才能进入临界区,进行直到退出,与mutex交替执行不同,临界区比较简单且最易用。
这里写图片描述


更多文章:http://blog.csdn.net/what951006?viewmode=list
powered by:小乌龟在大乌龟背上~

0 0
原创粉丝点击