zoukankan      html  css  js  c++  java
  • 秒杀多线程第七篇 经典线程同步 互斥量Mutex

    参考博客:http://blog.csdn.net/morewindows/article/details/7470936

    使用Mutex来解决资源的互斥访问

    互斥量也是一个内核对象,它用来确保一个线程独占一个资源的访问。互斥量与关键段的行为非常相似,并且互斥量可以用于不同进程中的线程互斥访问资源。使用互斥量Mutex主要将用到四个函数。

    第一个:创建互斥量

    HANDLECreateMutex(

    LPSECURITY_ATTRIBUTESlpMutexAttributes,

    BOOLbInitialOwner,     

    LPCTSTRlpName

    );

    第一个参数:安全控制传入NULL

    第二个参数:互斥量的拥有者  TRUE未触发状态 /NULL表示触发状态

    第三个参数:互斥量的名字 用来确定多进程的线程访问资源时,互斥量是同一个

    返回值:成功时返回互斥量句柄,失败时返回NULL

    第二个:打开互斥量

    HANDLEOpenMutex(

    DWORDdwDesiredAccess,

    BOOLbInheritHandle,

    LPCTSTRlpName     //名称

    );

    第一个参数:访问权限一般设置为MUTEX_ALL_ACCESS

    第二个参数:互斥量句柄的传承性 一般设置为TRUE

    第三个参数:互斥量的名称 进程中的线程可以通过这个名称来访问互斥量

    第三个:触发互斥量

    BOOLReleaseMutex (HANDLEhMutex)

    访问互斥资源前应该要调用等待函数,结束访问时就要调用ReleaseMutex()来表示自己已经结束访问,其它线程可以开始访问了

    第四个:清理互斥量

    CloseHandle()

    每个内核函数都可以用CloseHandle()来清理

    单独使用互斥量编写代码

    #include <stdio.h>
    
    #include <process.h>
    
    #include <windows.h>
    
    //定义事件句柄
    
    HANDLE  g_hThreadMutex;
    
    //定义CS段  
    
    CRITICAL_SECTION g_csThreadCode; 
    
    long g_num; //登录次数
    
    unsigned int __stdcall Fun(void *pPM); //线程函数
    
    const DWORD THREAD_NUM = 10;//启动线程数
    
    unsigned int __stdcall Fun(void *pPM)  
    
    {  
    
    //由于创建线程是要一定的开销的,所以新线程并不能第一时间执行到这来   
    
        int nThreadNum = *(int *)pPM; //子线程获取参数   
    
      //EnterCriticalSection(&g_csThreadCode);//进入关键段
    
      ReleaseMutex(g_hThreadMutex);
    
        Sleep(50);//some work should to do  
    
        g_num++;  //处理全局资源  
    
        Sleep(0);//some work should to do   
    
        printf("线程编号为%d  全局资源值为%d\n", nThreadNum, g_num);  
    
      //LeaveCriticalSection(&g_csThreadCode); //出关键段
    
        return 0;  
    
    } 
    
    int main()
    
    {
    
      printf("     互斥量Mutex的使用\n");
    
      g_num = 0;
    
      g_hThreadMutex=CreateMutex(NULL,FALSE,NULL);  //创建互斥量
    
      //InitializeCriticalSection(&g_csThreadCode); //初始化关键段
    
      HANDLE  handle[THREAD_NUM];
    
      int i=0;
    
      while (i<THREAD_NUM)
    
      {
    
        handle[i] = (HANDLE)_beginthreadex(NULL, 0, Fun, &i, 0, NULL);  
    
        i++;
    
        WaitForSingleObject(g_hThreadMutex,INFINITE);//2.等待事件被触发
    
      }
    
      
    
      WaitForMultipleObjects(THREAD_NUM, handle, TRUE, INFINITE);
    
      //DeleteCriticalSection(&g_csThreadCode); //销毁关键段
    
      for (i=0;i<THREAD_NUM;i++)
    
        CloseHandle(handle[i]);
    
      return 0;
    
    }
    运行结果为:
    1 

    为什么单独使用并不能解决对资源的保护?

    如果把注释的关键段CS去掉

    运行结果为:

    2

    此时实现了对资源的保护(互斥量的优势在于多进程间对资源的保护)

    由于互斥量常用于多进程之间的线程互斥,所以它比关键段还多一个很有用的特性——“遗弃”情况的处理。比如有一个占用互斥量的线程在调用ReleaseMutex()触发互斥量前就意外终止了(相当于该互斥量被“遗弃”了),那么所有等待这个互斥量的线程是否会由于该互斥量无法被触发而陷入一个无穷的等待过程中了?这显然不合理。因为占用某个互斥量的线程既然终止了那足以证明它不再使用被该互斥量保护的资源,所以这些资源完全并且应当被其它线程来使用。因此在这种“遗弃”情况下,系统自动把该互斥量内部的线程ID设置为0,并将它的递归计数器复置为0,表示这个互斥量被触发了。然后系统将“公平地”选定一个等待线程来完成调度(被选中的线程的WaitForSingleObject()会返回WAIT_ABANDONED_0)

  • 相关阅读:
    相信未来 ————11月份做题记录
    noi 滚cu后7月oi生活
    博客已经迁移到 http://imbotao.top 也会同步到这儿
    构建第一个SpringBoot工程
    Spring 事务管理
    IntelliJ IDEA 使用技巧
    JS 获取字符串实际长度
    读《程序员修炼之道》
    读《如何高效学习》
    SQL 语句优化方法
  • 原文地址:https://www.cnblogs.com/yuqilihualuo/p/3024313.html
Copyright © 2011-2022 走看看