当前位置: 代码迷 >> 综合 >> Windows中线程的基础知识和简单应用----互斥(Mutex)
  详细解决方案

Windows中线程的基础知识和简单应用----互斥(Mutex)

热度:12   发布时间:2024-01-09 02:52:21.0

和我一起住的同学从毕业开始就一直在使用COBOL语言。这是很老的一种开发语言了,当时被称为恐龙级别的东西。开始我不能理解为什么这么老的语言还一直在用呢。慢慢的从我同学那里知道,他们做的业务都是银行、证券、保险方面的项目。于是,我搜索了一下之后才知道,这是一种适用于商业和数据处理的一种语言。有一种说法是银行不到,就有COBOL”呵呵。(是不是有点跑题了,呵呵。别着急,等等)

 

去年我同学换了一个新工作,是给全球最大的保险公司做项目。随之而来的就是更新鲜的事情了。他们做开发的时候,只能在本机上进行编码,如果需要编译或调试的话,就要链接到外国的服务器上。于是,他们在本机上编码后都要反复的Review,然后用自己的账号登陆到外国服务器,进行编译。有一个问题,一直让他很郁闷。每次只能有一个可以链接到外国的服务器上,如果其他人想使用,就只能排队等待。当某一开发人员退出编译环境时,另一个人就可以占用编译器进行工作了。

 

每天下班回家后,都和我抱怨,这项目做的真麻烦,都啥时代了,怎么还想80年代似的,编译都要排队。

 

等一下,故事先讲到这里吧。大家是不是觉得他们这种方式有点像我们说过的线程同步呢。再想一下,是不是还有点像曾经说过的信号量呢。只不过,信号量是可以多个线程同时访问一个资源,而这里是只能有一个开发人员占用编译器。那么如果在创建信号量的时候,把信号量的值设置为1,就符合现在这个故事了。

 

在操作系统知识体系中存在一个互斥(Mutex)的概念。互斥也被当作二元信号灯。一个互斥基本上是一个多任务敏感的二元信号,它能用作同步多任务的行为,它常用作保护从中断来的临界段代码并且在共享同步使用的资源。

这里有涉及到了一个新名词----临界区,那么什么是临界区呢。

临界区:需要被多个线程访问的那段代码称为临界区(Critical Section)。

 

Windows系统中给我提供了一个CreateMutex()函数,用来创建一个互斥量。互斥也属于系统内核对象,创建成功后函数会返回一个句柄。同信号量一样,互斥不仅可以使用在多线程中,也可以在多进程中使用。函数声明如下:

HANDLE WINAPI CreateMutex( LPSECURITY_ATTRIBUTES lpMutexAttributes,
                                BOOL bInitialOwner,
                                LPCTSTR lpName);

lpMutexAttributes:设定安全属性。多数情况成NULL

bInitialOwner:如果设置为TRUE,那么创建该互斥的线程拥有这个互斥量。

LpNames:为创建的互斥量起一个名。其他线程或进程可以通过这个名字找到这个互斥量。

 

有了互斥量后,其他线程或进程通过OpenMutex()取得这个互斥量的句柄,进行判断是否可以进入临界区。使用后再调用ReleaseMutex()释放使用权。这两个函数声明如下:

HANDLE WINAPI OpenMutex( DWORD dwDesiredAccess,
                              BOOL bInheritHandle,
                              LPCTSTR lpName );

 

BOOL WINAPI ReleaseMutex( HANDLE hMutex);

 

除了用在线程同步中,很多情况下也在进程互斥中使用。当不希望用户可以开启两个实例的时候可以在程序的如果处,创建一个互斥量。如果用户开启两个实例的时候,第二个实例重复创建互斥量的时候就会失败,于是就可以断定是用户两次运行程序了。第二个实例的互斥量创建失败后,程序退出。功能完成,呵呵。

例子:

BOOL CTestThreadApp::InitInstance()

{

   ……

   ……

CWinApp::InitInstance();

HANDLE hMutex = CreateMutex(NULL, TRUE, APPMUTEX);

if(NULL == hMutex)

{

        return FALSE;

}

 

if(ERROR_ALREADY_EXISTS == ::GetLastError())

{

        return FALSE;

}

……

}

 

请注意:

if(ERROR_ALREADY_EXISTS == ::GetLastError())

{

    return FALSE;

}

 

当有重名的互斥量被创建时,CreateMutex()函数会返回互斥量的句柄。但是通过GetLastError()函数返回Error CodeERROR_ALREADY_EXISTS。当知道Error CodeERROR_ALREADY_EXISTS必然是用户启动了两个进程实例,于是后启动的那个实例退出。

 

 

  相关解决方案