昨天深夜整理了一下Judge的需求和存在的bug,发现自己在Judge这个泥潭里已经越陷越深,很多问题都不是用一种查阅式的阅读所能解决,所以决定仔细的读一读《Windows核心编程》,来深刻领悟一下Windows相关的编程知识。

一:3.2.2 关闭内核对象

《Windows核心编程》读书笔记(一)如果将一个无效句柄传递给CloseHandle,将会出现两种情况之一。如果进程运行正常,CloseHandle 返回FALSE ,而GetLastError 则返回ERROR_INVALID_HANDLE。如果进程正在排除错误,系统将通知调试程序,以便能排除它的错误。 
这个说明或许可以解释我Judge中现在存在的某个Bug:那个Bug仅在Debug模式下出现。

二:9.1等待函数

《Windows核心编程》读书笔记(一)下面这个函数Wa i t F o r M u l t i p l e O b j e c t s与Wa i t F o r S i n g l e O b j e c t函数很相似,区别在于它允许调用线程同时查看若干个内核对象的已通知状态:
《Windows核心编程》读书笔记(一)
《Windows核心编程》读书笔记(一)
《Windows核心编程》读书笔记(一)DWORD WaitForMultipleObjects(DWORD dwCount,
《Windows核心编程》读书笔记(一)   CONST HANDLE
* phObjects, 
《Windows核心编程》读书笔记(一)   BOOL fWaitAll, 
《Windows核心编程》读书笔记(一)   DWORD dwMilliseconds);
《Windows核心编程》读书笔记(一)d w C o u n t参数用于指明想要让函数查看的内核对象的数量。这个值必须在1与M A X I M U M _WA I T _ O B J E C T S(在Wi n d o w s头文件中定义为6 
4)之间。p h O b j e c t s参数是指向内核对象句柄的数组的指针。
《Windows核心编程》读书笔记(一)可以以两种不同的方式来使用Wa i t F o r M u l t i p l e O b j e c t s函数。一种方式是让线程进入等待状态,直到指定内核对象中的任何一个变为已通知状态。另一种方式是让线程进入等待状态,直到所有指定的内核对象都变为已通知状态。f Wa i tAl l参数告诉该函数,你想要让它使用何种方式。如果为该参数传递T R U E,那么在所有对象变为已通知状态之前,该函数将不允许调用线程运行。
《Windows核心编程》读书笔记(一)
《Windows核心编程》读书笔记(一)d w M i l l i s e c o n d s参数的作用与它在Wa i t F o r S i n g l e O b j e c t中的作用完全相同。如果在等待的时候规定的时间到了,那么该函数无论如何都会返回。同样,通常为该参数传递I N F I N I T E,但是在编写代码时应该小心,以避免出现死锁情况。
《Windows核心编程》读书笔记(一)
《Windows核心编程》读书笔记(一)Wa i t F o r M u l t i p l e O b j e c t s函数的返回值告诉调用线程,为什么它会被重新调度。可能的返回值是WA I T _ FA I L E D和WA I T _ T I M E O U T,这两个值的作用是很清楚的。如果为f Wa i tAl l参数传递T R U E,同时所有对象均变为已通知状态,那么返回值是WA I T _ O B J E C T _ 
0。如果为f Wa i t A l l传递FA L S E,那么一旦任何一个对象变为已通知状态,该函数便返回。在这种情况下,你可能想要知道哪个对象变为已通知状态。返回值是WA I T _ O B J E C T _ 0与(WA I T _ O B J E C T _ 0 + d w C o u n t - 1)之间的一个值。换句话说,如果返回值不是WA I T _ T I M E O U T,也不是WA I T _ FA I L E D,那么应该从返回值中减去WA I T _ O B J E C T _ 0。产生的数字是作为第二个参数传递给Wa i t F o r M u l t i p l e O b j e c t s的句柄数组中的索引。该索引说明哪个对象变为已通知状态。下面是说明这一情况的一些示例代码:
《Windows核心编程》读书笔记(一)
《Windows核心编程》读书笔记(一)
《Windows核心编程》读书笔记(一)HANDLE h[
3];
《Windows核心编程》读书笔记(一)h[
0= hProcess1;
《Windows核心编程》读书笔记(一)h[
1= hProcess2;
《Windows核心编程》读书笔记(一)h[
2= hProcess3;
《Windows核心编程》读书笔记(一)DWORD dw 
= WaitForMultipleObjects(3, h, FALSE, 5000);
《Windows核心编程》读书笔记(一)
switch(dw) 
。除非删除已经收到通知的句柄,否则代码就无法正确地运行。

用WaitForMultipleObjects改写我的Judge,使得中止线程时,可以让线程自己中止,而不是由其他线程杀。这样可以解决另一Bug。

三:17.1.2 在可执行文件或DLL的多个实例之间共享静态数据

《Windows核心编程》读书笔记(一)我可以创建一个称为“S h a r e d”的节,它包含单个L O N G值,如下所示:
《Windows核心编程》读书笔记(一)
《Windows核心编程》读书笔记(一)#pragma data_seg(
"Shared")
《Windows核心编程》读书笔记(一)LONG g_lInstanceCount 
= 0;
《Windows核心编程》读书笔记(一)#pragma data_seg()
《Windows核心编程》读书笔记(一)当编译器对这个代码进行编译时,它创建一个新节,称为S h a r e d,并将它在编译指示后面看到的所有已经初始化(i n i t i a l i z e d)的数据变量放入这个新节中。在上面这个例子中,变量放入S h a r e d节中。该变量后面的#pragma dataseg()一行告诉编译器停止将已经初始化的变量放入S h a r e d节,并且开始将它们放回到默认数据节中。需要记住的是,编译器只将已经初始化的变量放入新节中。例如,如果我从前面的代码段中删除初始化变量(如下面的代码所示),那么编译器将把该变量放入S h a r e d节以外的节中。
《Windows核心编程》读书笔记(一)
《Windows核心编程》读书笔记(一)#pragma data_seg(
"Shared")
《Windows核心编程》读书笔记(一)LONG g_lInstanceCount;
《Windows核心编程》读书笔记(一)#pragma data_seg()
《Windows核心编程》读书笔记(一)Microsoft 的Visual C
++编译器提供了一个A l l o c a t e说明符,使你可以将未经初始化的数据放入你希望的任何节中。请看下面的代码:
《Windows核心编程》读书笔记(一)
《Windows核心编程》读书笔记(一)
// Create Shared section & have compiler place initialized data in it.
《Windows核心编程》读书笔记(一)
#pragma data_seg("Shared")
《Windows核心编程》读书笔记(一)
《Windows核心编程》读书笔记(一)
// Initialized, in Shared section
《Windows核心编程》读书笔记(一)
int a = 0;
《Windows核心编程》读书笔记(一)
《Windows核心编程》读书笔记(一)
// Uninitialized, not in Shared section
《Windows核心编程》读书笔记(一)
int b;
《Windows核心编程》读书笔记(一)
《Windows核心编程》读书笔记(一)
// Have compiler stop placing initialized data in Shared section.
《Windows核心编程》读书笔记(一)
#pragma data_seg()
《Windows核心编程》读书笔记(一)
《Windows核心编程》读书笔记(一)
// Initialized, in Shared section
《Windows核心编程》读书笔记(一)
__declspec(allocate("Shared")) int c = 0;
《Windows核心编程》读书笔记(一)
《Windows核心编程》读书笔记(一)
// Uninitialized, in Shared section
《Windows核心编程》读书笔记(一)
__declspec(allocate("Shared")) int d;
《Windows核心编程》读书笔记(一)
《Windows核心编程》读书笔记(一)
// Initialized, not in Shared section
《Windows核心编程》读书笔记(一)
int e = 0;
《Windows核心编程》读书笔记(一)
《Windows核心编程》读书笔记(一)
// Uninitialized, not in Shared section
《Windows核心编程》读书笔记(一)
int f;        
《Windows核心编程》读书笔记(一)上面的注释清楚地指明了指定的变量将被放入哪一节。若要使A l l o c a t e声明的规则正确地起作用,那么首先必须创建节。如果删除前面这个代码中的第一行#pragma data_seg,上面的代码将不进行编译。
《Windows核心编程》读书笔记(一)之所以将变量放入它们自己的节中,最常见的原因也许是要在. e x e或D L L文件的多个映像之间共享这些变量。按照默认设置, . e x e或D L L文件的每个映像都有它自己的一组变量。然而,可以将你想在该模块的所有映像之间共享的任何变量组合到它自己的节中去。当给变量分组时,系统并不为. e x e或D L L文件的每个映像创建新实例。
《Windows核心编程》读书笔记(一)
《Windows核心编程》读书笔记(一)仅仅告诉编译器将某些变量放入它们自己的节中,是不足以实现对这些变量的共享的。还必须告诉链接程序,某个节中的变量是需要加以共享的。若要进行这项操作,可以使用链接程序的命令行上的
/ S E C T I O N开关:
《Windows核心编程》读书笔记(一)
《Windows核心编程》读书笔记(一)
《Windows核心编程》读书笔记(一)
/SECTION:name,attributes
《Windows核心编程》读书笔记(一)在冒号的后面,放入你想要改变其属性的节的名字。在我们的例子中,我们想要改变S h a r e d节的属性。因此应该创建下面的链接程序开关:
《Windows核心编程》读书笔记(一)
《Windows核心编程》读书笔记(一)
/SECTION:Shared,RWS
《Windows核心编程》读书笔记(一)在逗号的后面,我们设定了需要的属性。用R代表R E A D ,W代表W E I T E,E代表E X E C U T E,S代表S H A R E D。上面的开关用于指明位于S h a r e d节中的数据是可以读取、写入和共享的数据。如果想要改变多个节的属性,必须多次设定
/ S E C T I O N开关,也就是为你要改变属性的每个节设定一个/ S E C T I O N开关。
《Windows核心编程》读书笔记(一)也可以使用下面的句法将链接程序开关嵌入你的源代码中:
《Windows核心编程》读书笔记(一)
《Windows核心编程》读书笔记(一)
《Windows核心编程》读书笔记(一)#pragma comment(linker, 
"/SECTION:Shared,RWS")
《Windows核心编程》读书笔记(一)这一行代码告诉编译器将上面的字符串嵌入名字为“ . d r e c t v e”的节。当链接程序将所有的. o b j模块组合在一起时,链接程序就要查看每个. o b j模块的“ . d r e c t v e”节,并且规定所有的字符串均作为命令行参数传递给该链接程序。我一直使用这种方法,因为它非常方便。如果将源代码文件移植到一个新项目中,不必记住在Visual C
++的Project Settings(项目设置)对话框中设置链接程序开关。
《Windows核心编程》读书笔记(一)虽然可以创建共享节,但是,由于两个原因, M i c r o s o f t并不鼓励你使用共享节。第一,用这种方法共享内存有可能破坏系统的安全。第二,共享变量意味着一个应用程序中的错误可能影响另一个应用程序的运行,因为它没有办法防止某个应用程序将数据随机写入一个数据块。《Windows核心编程》读书笔记(一)


用这个方法可以在两个进程间共享内存数据。

相关文章: