最近在研究《Windows核心编程》,留意到书中涉及到的两个知识点可以解决这个问题,觉得蛮有意思的,就记录下来,和大家分享下。
第一种方法:采用线程同步中的互斥量内核对象
互斥量(mutex)内核对象用来确保一个线程独占对一个资源的访问。 --------《Windows核心编程》
互斥量对象包含一个使用计数,线程ID以及一个递归函数。 --------《Windows核心编程》
涉及到的函数
HANDLE CreateMutex(
PSECURITY_ATTRIBUTES psa,
BOOL bInitialOwner,
PCTSTR pszName,
);
psa为安全属性,只要见到PSECURITY_ATTRIBUTES这个数据类型那就说明该函数涉及内核对象,所有的内核对象的创建函数都会有这个属性。
bInitialOwner 如果该值为TRUE时,线程则立即拥有该互斥量,递归计数将被设为1,如果为FALSE,互斥量对象的线程ID和递归计数都将设置为0,互斥量处于触发状态。
pszName指定互斥体对象的名字。
BOOL ReleaseMutex(HANDLE hMutex);释放互斥量。
CloseHandle(HANDLE) 清理句柄
代码示例:
实验思路,先用VS2010创建一个win32程序,程序的主窗口以及消息循环向导程序已经创立完毕,我们只需在程序的入口处创建一个互斥量,再程序退出时释放互斥量就可以了。如果在创建过程中互斥量已经存在,则调用GetLastError()会返回ERROR_ALREADY_EXISTS
还有在程序结束前别忘记要释放互斥量以及CloseHandle();
运行结果:
运行一个实例
再运行一个实例的时候
出现这个提示,确定后程序直接退出。
第二种方法:采用内存映射文件共享数据段
当我们运行一个程序的时候,内存首先要将exe或DLL装载入内存中。.exe和DLL文件映像是由许多段组成,
每个标准的段名都以点号开始。例如。在编译程序的时候,编译器会将代码放在一个名叫.text的段中。再如
可执行文件的常用段
.bbs 未经初始化的数据
.CRT 只读的C运行时数据
.date 已初始化的数据
...............
除了这些标准的段外,Microsoft还允许我们创建自己的段。
#pragma data_seg("sectionname");
那么我们就可以创建一个自定义段, 包含一个Long变量
#pragma date_seg("Shared")
volatile LONG m_share_data=0;
#pragma date_seg("Shared")
如果将Shared这个段设置为共享的话,那么所有该程序的实例都会共享这个数据段,这样就可以通过m_sharea_date
来获得运行实例的数量。
#pragma comment(linker,"/SECTION:Shared,RWS");
R表示Read,W表示WRITE,E表示EXECUTE,S表示SHARED
代码示例:
实验思路,创建一个共享数据段,在共享数据段里声明一个long的数据m_share_data,当第一个实例运行的时候将m_share_data加1 ,每次程序运行都会检测这个值,如果大于1那就表示已经有一个实例在运行了。
运行结果:
再运行一个实例的时候
总结:
线程同步分为用户模式的线程同步以及内核模式的线程同步,互斥量只是内核模式线程同步中的一种,
而内存映射则是属于内存管理的范畴,这里提到的只是其中一个很小的知识点,也就是为大家更好的理解Windows编程起到一个抛砖引玉的作用吧。