引子:话说三国时期蜀国猛将张飞在汉中时于宕渠与魏国猛将张郃大战,酣战十个回合,张飞佯败退走,躲在隐蔽处。其目的是等待增援部队的到来。张飞等啊等,终于看到前方有一支军队,但是他立马傻眼了,前方军队没有旗号,不知是敌是友。于是张飞开始骂娘了,狗日的尼玛军队连旗子也没有。我们假设一下情景:如果张飞没有看到增援部队他是不会轻举妄动的;如果看到增援部队,而且是打的是他的旗号,他会立马毫不迟疑的杀回去;如果看到前方有军队,但是打的不是他的旗号,他会按兵不动,继续等待增援部队。。。今天要讲的命名内核对象共享,也是这个道理,只有遇到旗号一致的军队时才会有所行动,否则一直按兵不动。
下面给出代码,以互斥量的名字作为旗号。关于互斥量可以参考前面的博客:白话windows多线程同步之互斥变量
第一个进程:
#include "stdafx.h"
#include <Windows.h>
#include <process.h>
#include <time.h>
HANDLE g_hMutext = NULL ;
DWORD WINAPI Fun(LPVOID lp)
{
WaitForSingleObject(g_hMutext, INFINITE) ;
printf("%d doing something now in Process Id %d\n", GetCurrentThreadId(), GetCurrentProcessId()) ;
Sleep(1000 * 20) ;
printf("%d has Finished in Process Id %d\n", GetCurrentThreadId(), GetCurrentProcessId()) ;
time_t ct ;
tm *ctm ;
time(&ct) ;
ctm = localtime(&ct) ;
printf("The Current time is %02d:%02d:%02d\n", ctm->tm_hour, ctm->tm_min, ctm->tm_sec) ;
ReleaseMutex(g_hMutext) ;
return 0 ;
}
int _tmain(int argc, _TCHAR* argv[])
{
g_hMutext = CreateMutex(NULL, FALSE, _T("ShonmMutext")) ;
CreateThread(NULL, 0, Fun, NULL, 0, NULL) ;
while(TRUE)
{
}
return 0;
}
第二个进程:
#include "stdafx.h"
#include <Windows.h>
#include <process.h>
#include <time.h>
HANDLE g_hMutext = NULL ;
DWORD WINAPI Fun(LPVOID lp)
{
WaitForSingleObject(g_hMutext, INFINITE) ;
printf("Because a thread in another process has finished, I have chance to process now\n") ;
time_t ct ;
tm *ctm ;
time(&ct) ;
ctm = localtime(&ct) ;
printf("The Current time is %02d:%02d:%02d\n", ctm->tm_hour, ctm->tm_min, ctm->tm_sec) ;
printf("%d doing something now in Process Id %d\n", GetCurrentThreadId(), GetCurrentProcessId()) ;
Sleep(1000 * 20) ;
printf("%d has Finished in Process Id %d\n", GetCurrentThreadId(), GetCurrentProcessId()) ;
ReleaseMutex(g_hMutext) ;
return 0 ;
}
int _tmain(int argc, _TCHAR* argv[])
{
g_hMutext = CreateMutex(NULL, FALSE, _T("ShonmMutext")) ;
CreateThread(NULL, 0, Fun, NULL, 0, NULL) ;
while(TRUE)
{
}
return 0;
}
请看运行效果:
我们看到当5852进程中的线程7716结束后(时间是11:06:29),进程7252中的线程5736同时开始获得该互斥量,说明该互斥量成功的被两个进程共享。使用的方式也很简单,就是给创建的内核对象命一个相同的名字,这样就相当于是一家人了,援兵已到,立马行动,哈哈。
哪些对象可以被命名?
创建内核对象函数有一个名字参数的都可以。以下函数都可以:
HANDLE CreateMutex( PSLCURITY_ATTRIBUTES psa, BOOL bInitialOwner, PCTSTR pszName); HANDLE CreateEvent( PSECURITY_ATTRIBUTES psa, BOOL bManualReset, BOOL bInitialState, PCTSTR pszName); HANDLE CreateSemaphore( PSECURITY_ATTRIBUTES psa, LONG lInitialCount, LONG lMaximumCount, PCTSTR pszNarne); HANDLE CreateWaitableTimer( PSLCURITY_ATTRIBUTES psa, BOOL bManualReset, PCTSTR pszName); HANDLE CreateFileMapping( HANDLE hFile, PSECURITY_ATTRIBUTES psa, DWORD flProtect, DWORD dwMaximumSizeHigh, DWORD dwMaximumSizeLow, PCTSTR pszName); HANDLE CreateJobObject( PSECURITY_ATTRIBUTES psa, PCTSTR pszName);
现在我们探讨以下,为什么可以这样做?一个进程中的对象是如何被另一个进程认识?那是因为内核对象由内核即操作系统拥有,而不是进程拥有。进程只是拥有一个句柄表,当进程调用创建内核的函数时,操作系统会将刚才产生的内核对象的索引添加到进程的句柄表中。如果创建时的内核对象是命名的,那么当第二次创建该命名的内核对象时(不管是在该进程中,还是在其他进程中),只是打开已被创建的内核对象,由于内核对象都是系统级别的,当然可以被进程共享。