互斥(Mutex)是一种用途非常广泛的内核对象。能够保证多个线程对同一共享资源的互斥访问。同临界区有些类似,只有拥有互斥对象的线程才具有访问资源的权限,由于互斥对象只有一个,因此就决定了任何情况下此共享资源都不会同时被多个线程所访问。当前占据资源的线程在任务处理完后应将拥有的互斥对象交出,以便其他线程在获得后得以访问资源。与其他几种内核对象不同,互斥对象在操作系统中拥有特殊代码,并由操作系统来管理,操作系统甚至还允许其进行一些其他内核对象所不能进行的非常规操作。

  只有拥有互斥对象并得以进入到共享资源,而其他线程则会被排斥在外。当此线程处理完共享资源并准备离开此区域时将把其所拥有的互斥对象交出,其他任何一个试图访问此资源的线程都有机会得到此互斥对象。

  以互斥内核对象来保持线程同步可能用到的函数主要有CreateMutex()、OpenMutex()、ReleaseMutex()、WaitForSingleObject()和WaitForMultipleObjects()等。在使用互斥对象前,首先要通过CreateMutex()或OpenMutex()创建或打开一个互斥对象。CreateMutex()函数原型为:

  1. HANDLE CreateMutex(
  2. LPSECURITY_ATTRIBUTES lpMutexAttributes, // 安全属性指针
  3. BOOL bInitialOwner,           // 初始拥有者
  4. LPCTSTR lpName                // 互斥对象名
  5. );

  参数bInitialOwner主要用来控制互斥对象的初始状态。一般多将其设置为FALSE,以表明互斥对象在创建时并没有为任何线程所占有。如果在创建互斥对象时指定了对象名,那么可以在本进程其他地方或是在其他进程通过OpenMutex()函数得到此互斥对象的句柄。OpenMutex()函数原型为:

  1. HANDLE OpenMutex(
  2. DWORD dwDesiredAccess, // 访问标志
  3. BOOL bInheritHandle,  // 继承标志
  4. LPCTSTR lpName      // 互斥对象名
  5. );

  当目前对资源具有访问权的线程不再需要访问此资源而要离开时,必须通过ReleaseMutex()函数来释放其拥有的互斥对象,其函数原型为:

  1. BOOL ReleaseMutex(HANDLE hMutex);  //待释放的互斥对象句柄

  至于WaitForSingleObject() 和WaitForMultipleObjects() 等待函数在互斥对象保持线程同步中所起的作用与在其他内核对象中的作用是基本一致的,也是等待互斥内核对象的通知。但是这里需要特别指出的是:在互斥对象通知引起调用等待函数返回时,等待函数的返回值不再是通常的WAIT_OBJECT_0(对于WaitForSingleObject()函数)或是在WAIT_OBJECT_0到WAIT_OBJECT_0+nCount-1之间的一个值(对于WaitForMultipleObjects()函数),而是将返回一个WAIT_ABANDONED_0(对于WaitForSingleObject()函数)或是在WAIT_ABANDONED_0到WAIT_ABANDONED_0+nCount-1之间的一个值(对于WaitForMultipleObjects()函数)。以此来表明线程正在等待的互斥对象由另外一个线程所拥有,而此线程却在使用完共享资源前就已经终止。除此之外,使用互斥对象的方法在等待线程的可调度性上同使用其他几种内核对象的方法也有所不同,其他内核对象在没有得到通知时,受调用等待函数的作用,线程将会挂起,同时失去可调度性,而使用互斥的方法却可以在等待的同时仍具有可调度性,这也正是互斥对象所能完成的非常规操作之一。
  在编写程序时,互斥对象多用在对那些为多个线程所访问的内存块的保护上,可以确保任何线程在处理此内存块时都对其拥有可靠的独占访问权。下面给出的示例代码即通过互斥内核对象hMutex对共享内存快g_cArray[]进行线程的独占访问保护。下面给出实现代码清单:

  1. // 互斥对象
  2. HANDLE hMutex = NULL;
  3. char g_cArray[];
  4. UINT ThreadProc18(LPVOID pParam)
  5. {
  6.  // 等待互斥对象通知
  7.  WaitForSingleObject(hMutex, INFINITE);
  8.  // 对共享资源进行写入操作
  9.  for (int i = ; i < ; i++)
  10.  {
  11.   g_cArray[i] = 'a';
  12.   Sleep();
  13.  }
  14.  // 释放互斥对象
  15.  ReleaseMutex(hMutex);
  16.  return ;
  17. }
  18. UINT ThreadProc19(LPVOID pParam)
  19. {
  20.  // 等待互斥对象通知
  21.  WaitForSingleObject(hMutex, INFINITE);
  22.  // 对共享资源进行写入操作
  23.  for (int i = ; i < ; i++)
  24.  {
  25.   g_cArray[ - i - ] = 'b';
  26.   Sleep();
  27.  }
  28.  // 释放互斥对象
  29.  ReleaseMutex(hMutex);
  30.  return ;
  31. }
  32. ……
  33. void CSample08View::OnMutex()
  34. {
  35.  // 创建互斥对象
  36.  hMutex = CreateMutex(NULL, FALSE, NULL);
  37.  // 启动线程
  38.  AfxBeginThread(ThreadProc18, NULL);
  39.  AfxBeginThread(ThreadProc19, NULL);
  40.  // 等待计算完毕
  41.  Sleep();
  42.  // 报告计算结果
  43.  CString sResult = CString(g_cArray);
  44.  AfxMessageBox(sResult);
  45. }

  互斥对象在MFC中通过CMutex类进行表述。使用CMutex类的方法非常简单,在构造CMutex类对象的同时可以指明待查询的互斥对象的名字,在构造函数返回后即可访问此互斥变量。CMutex类也是只含有构造函数这唯一的成员函数,当完成对互斥对象保护资源的访问后,可通过调用从父类CSyncObject继承的UnLock()函数完成对互斥对象的释放。CMutex类构造函数原型为:
CMutex( BOOL bInitiallyOwn = FALSE, LPCTSTR lpszName = NULL,LPSECURITY_ATTRIBUTES lpsaAttribute = NULL );

  该类的适用范围和实现原理与API方式创建的互斥内核对象是完全类似的,但要简洁的多,下面给出就是对前面的示例代码经CMutex类改写后的程序实现清单:

  1. // MFC互斥类对象
  2. CMutex g_clsMutex(FALSE, NULL);
  3. UINT ThreadProc27(LPVOID pParam)
  4. {
  5.  // 等待互斥对象通知
  6.  g_clsMutex.Lock();
  7.  // 对共享资源进行写入操作
  8.  for (int i = ; i < ; i++)
  9.  {
  10.   g_cArray[i] = 'a';
  11.   Sleep();
  12.  }
  13.  // 释放互斥对象
  14.  g_clsMutex.Unlock();
  15.  return ;
  16. }
  17. UINT ThreadProc28(LPVOID pParam)
  18. {
  19.  // 等待互斥对象通知
  20.  g_clsMutex.Lock();
  21.  // 对共享资源进行写入操作
  22.  for (int i = ; i < ; i++)
  23.  {
  24.   g_cArray[ - i - ] = 'b';
  25.   Sleep();
  26.  }
  27.  // 释放互斥对象
  28.  g_clsMutex.Unlock();
  29.  return ;
  30. }
  31. ……
  32. void CSample08View::OnMutexMfc()
  33. {
  34.  // 启动线程
  35.  AfxBeginThread(ThreadProc27, NULL);
  36.  AfxBeginThread(ThreadProc28, NULL);
  37.  // 等待计算完毕
  38.  Sleep();
  39.  // 报告计算结果
  40.  CString sResult = CString(g_cArray);
  41.  AfxMessageBox(sResult);
  42. }

互斥对象 Mutex 和MFC中的CMutex的更多相关文章

  1. 第9章 用内核对象进行线程同步(3)_信号量(semaphore)、互斥对象(mutex)

    9.5 信号量内核对象(Semaphore) (1)信号量的组成 ①计数器:该内核对象被使用的次数 ②最大资源数量:标识信号量可以控制的最大资源数量(带符号的32位) ③当前资源数量:标识当前可用资源 ...

  2. 深入理解Solaris内核中互斥锁(mutex)与条件变量(condvar)之协同工作原理

    在Solaris上写内核模块总是会用到互斥锁(mutex)与条件变量(condvar), 光阴荏苒日月如梭弹指一挥间,Solaris的大船说沉就要沉了,此刻心情不是太好(Orz).每次被年轻的有才华的 ...

  3. Linux系统中的信号量(semphore)与互斥体(mutex)

    http://www.embexperts.com/viewthread.php?tid=31 两者最大区别:信号量可以允许多个线程进入临界区,而互斥体只允许一个线程进入临界区.本贴将描述信号量与互斥 ...

  4. 在MFC中实现对象之间数据的传递。

    方法一: 第一步:在VS2010里面新建一个单文档MFC程序. 第二步:在App类里面的头文件里面 定义性声明一个变量 ,见下面程序 public: CString ii; 第三步:在App类的实现文 ...

  5. MFC中获取各个窗口之间的句柄或者指针对象的方法

    MFC在非常多的对话框操作中,我们常常要用到在一个对话框中调用还有一个对话框的函数或变量.能够用例如以下方法来解决.    HWND hWnd=::FindWindow(NULL,_T("S ...

  6. MFC中线程相关知识

    MFC中把线程分为两种类型,UI线程和工作者线程. MFC中启动一个线程的最好方法是调用AfxBeginThread,有两个版本,一个用于启动Ui线程,另外一个用于启动工作者线程.在MFC程序中,只有 ...

  7. 多线程相关------互斥量Mutex

    互斥量(Mutex) 互斥量是一个可以处于两态之一的变量:解锁和加锁.只有拥有互斥对象的线程才具有访问资源的权限.并且互斥量可以用于不同进程中的线程的互斥访问. 相关函数: CreateMutex用于 ...

  8. 经典线程同步 互斥量Mutex

    阅读本篇之前推荐阅读以下姊妹篇: <秒杀多线程第四篇一个经典的多线程同步问题> <秒杀多线程第五篇经典线程同步关键段CS> <秒杀多线程第六篇经典线程同步事件Event& ...

  9. 转:MFC中创建多线程

    MFC中创建多线程   MFC的多线程函数必须声明为静态的或者是全局函数(不同的在于全局函数不能访问类的私有静态成员,而静态类函数可以):但这样的线程函数只能访问静态的成员变量,要实现访问类的其他成员 ...

随机推荐

  1. SSH登录很慢问题的解决

    用ssh连其他linux机器,会等待10-30秒才有提示输入密码.严重影响工作效率.登录很慢,登录上去后速度正常,这种情况主要有两种可能的原因: 1. DNS反向解析的问题 OpenSSH在用户登录的 ...

  2. Cpk

    CPK:Complex Process Capability index 的缩写,是现代企业用于表示制程能力的指标.制程能力是过程性能的允许最大变化范围与过程的正常偏差的比值.制程能力研究在於确认这些 ...

  3. IREP_SOA Integration WSDL概述(概念)

    20150827 Created By BaoXinjian

  4. POJ 3311 Hie with the Pie(Floyd+状态压缩DP)

    题是看了这位的博客之后理解的,只不过我是又加了点简单的注释. 链接:http://blog.csdn.net/chinaczy/article/details/5890768 我还加了一些注释代码,对 ...

  5. php 快速fork出指定个子进程

    $pids = array(); $child_pid = pcntl_fork(); if ($child_pid == -1) { throw new Exception( __METHOD__ ...

  6. TestNG:org.openqa.selenium.firefox.NotConnectedException: Unable to connect

    http://blog.sina.com.cn/s/blog_68f262210102vgzj.html 今天在尝试着用TestNG写一下自动化测试用例,以前也写过,不过用的是经常封装的代码,现在完全 ...

  7. spring错误<context:property-placeholder>:Could not resolve placeholder XXX in string value XXX

    spring同时集成redis和mongodb时遇到多个资源文件加载的问题 这两天平台中集成redis和mongodb遇到一个问题 单独集成redis和单独集成mongodb时都可以正常启动程序,但是 ...

  8. javascript delete方法

    学习delete可以参考下面两个博客,写的都很好,本文大部分参考与以下两个博客 http://www.cnblogs.com/windows7/archive/2010/03/28/1698387.h ...

  9. gRPC java 客户端,服务器端通讯使用json格式

    使用 protobuf 作为通讯内容序列化的简单例子请看:http://www.cnblogs.com/ghj1976/p/5458176.html . 本文是使用 json 做为内容序列化的简单例子 ...

  10. VisualVM 性能分析概述

    VisualVM是一个免费的Java应用监控.分析工具. 简单说来,VisualVM是一种集成了多个JDK命令行工具的可视化工具,它能为您提供强大的分析能力.所有这些都是免费的!它囊括的命令行工具包括 ...