现在的计算机大都采用多CPU或多核处理器,所以编程时尤其是在编写游戏或虚拟现实相关的程序时一定要充分发挥多核的能力,以加快程序运行速度,提高性能。常见的做法便是编写多线程的程序:在主线程中进行AI、碰撞检测和物理方面的计算,而在其它线程中进行渲染所需要的数据更新,比如计算各个Billboard的顶点坐标等等。
本文不讨论线程划分和线程负载的平衡问题。只简要说明在Windows系统中创建关闭线程及如何在线程中正确的使用Sleep函数。
1. 创建线程:用_beginthreadex(…)函数,此函数比具有同样功能的CreateThread(…)函数更安全。在微软Visual Studio .Net 2003的文档中说过用CreateThread创建线程后,用相应的ExitThread关闭线程时会出现小的内存泄露。
2. 关闭线程:用_endthreadex(…)函数。
3. Sleep的使用-举例说明
(1)虚拟现实程序中一个线程用于从硬件采集数据,隔20ms采集一次。
这样我们可以在采集的线程调用Sleep(20),使得每采集一次数据后线程休息20ms。采集到的数据存在一个全局变量中,主线程每次都使用全局变量中的值。主线程的周期可以不与采集线程同步。
(2)图形程序中我们将某些复杂的生成顶点数据的算法放在辅线程里,可以在主线程进行AI运算的同时,辅线程进行生成顶点的运算(如计算噪声来生成顶点)。此时要求主线程走一个周期,辅线程的顶点更新也是一个周期。
这样我们可以在生成顶点的辅线程中调用Sleep(0),并用一个全局的BOOL变量来控制两个周期的同步。
Sleep(0)将线程剩下的时间片奉献给其他已经准备好的线程去用。
代码示例如下:
//噪声生成顶点的线程
while(线程没有退出)
{
runOneStep();//计算噪声生成顶点
times++;
g_bStepComplete = true;
while(g_bStepComplete)
Sleep(0);//如果主线程还没利用新顶点,则此线程休息
}
//主线程
while(...)
{
AISimu();//AI的计算
while(!g_bStepComplete)
sleep(0); //如果生成顶点线程没有计算完则等待
copyVBToBuffer(); //将顶点线程生成的数据拷贝到渲染要用的Buffer中
g_bStepComplete = false;//利用了新顶点后将标志变量复位
Render(); //渲染
}
4. 线程的安全问题十分重要。当多个线程同时操作一段数据时,安全起见,线程间的互斥是必不可少的。我通常利用thread mutex来做, 在此不再叙述。