《Windows游戏编程大师技巧》(第二版)第11章(38) 为实现这类资源管理程序并正确地共享线程,我们需要创建一个变量来跟踪其他使用该资源的线程。任何需要使用该资源的线程都必须检测该变量,之后才能使用它。当然,这依然是个问题,除非这个变量能够被检测或独立(Atomically)地修改,因为你可能正修改一个变量进行到一半而其他线程恰在这时获得控制权。可以将这类变量设置为volatile类型以将其问题发生概率最小化,这样便告知编译器不要为其进行内存拷贝。然而,最终你还不得不使用信号量(Semaphores,一个简单的类似于全局变量的计数器,但却是以不能被打断的基本汇编代码形式存在)、互斥体(Mutex,只允许一个线程访问临界区,是二进制的信号量)、临界区(Critical Section,指定编译器在编译Win32调用时一次只能允许一个线程)等等。另一方面,如果每一个线程的功能相对比较独立,也就不必过多考虑这些。DEMO11_10.CPPEXE是一个应用多线程编程的DirectX实例(其16位版本是DEMO11_10_16B.CPPEXE),读者可以检验一下该程序。该程序创建了许多外星BOB(Blitter Object),并使它们围绕主线运动。此外该程序还创建了另外一个线程以动态改变这些BOB的颜色。这是一个非常简单、安全的多线程程序范例。最后要确保将该程序连上所有DirectX .LIB文件。但是,如果有许多线程都调用同一函数,就会产生可重入性(Reentrancy)的问题。需要重入的函数必须要有状态信息,而且不能使用可能会被具有抢占优先权的线程进出程序时破坏的全局变量。此外,如果使用线程来使DirectX对象自己动起来,表面事故、计时及同步过程很可能会出错。因此建议读者严格限制使用线程来处理那些在很大程度上是独立的、只存在于它们自己的“状态空间”中的并且不需要以精确频率运行的对象。高级多线程编程好了!本章到此也告一段落。因为接下来我们只能探讨竞争条件、死锁、临界区、互斥体、信号量以及许多令人头疼的问题。澄清所有这些问题(除了最后一个)都会有助于读者编写无错的多线程程序。当然,即使对此一无所知,读者仍然能够依据常识编写出基本安全的多线程程序,记住任何线程都可能会随时被其他线程打断这个道理。注意你编写的线程是如何访问共享数据结构的。尽可能以独立且自动的方式进行这些操作。确保这样的事情不会发生:一个线程修改变量,而另一个线程错误地使用了正被修改到一半的变量。同时,除本章提及的函数调用外,还有几个基本函数调用没有提及,如ExitThread()和GetThreadExitCode(),但这几个函数相对比较简单易于理解,并可以在你的API参考书中查到它们。总结本章内容读来比较轻松,没有太多的技术术语,只是一顿丰富的知识大餐。我形容它为大餐,呃,大概是因为我在写作过程中吃了太多Power Bar速食条了。言归正传,本章中我们接触了许多基础知识:如数据结构、内存管理、递归、分析、定点数运算和多线程。其中有些内容乍看与游戏似乎关系不大,但确实相关。要制作一个游戏,我们必须了解编程的每一方面——因为游戏的确是如此复杂!现在本章告一段落,我要出门去租《2001: A Space Odyssey》回来看了,因为下一章我们将探讨人工智能……