例子1 对于许多人来说,要从一个单一的进程中创建多个线程的话,在观念上就要做一些改变。我们首先来看几个非常简单的例子,了解一下Win32 API中线程的基本运作是怎样的。
以下的代码是一个非常简单的单线程程序。在这个程序中,用户每按下回车键一次,就会输出全局变量count的值。由于在程序中并没有改变count的值,因此该程序一直输出0。这里并没有使用什么技巧:
#include #include
UINT count;
void main(void) { CHAR retStr[100];
count=0; while(1) { cout << "Press to display the count... "; cin.getline(retStr, 100); cout << "The count is: " << count << endl << endl; } }
|
现在要为这些代码增加一个线程。NT中的线程其实就是后台中执行的一个函数。代码中的CountThread函数增加全局变量count的值,然后休眠100毫秒。在你运行程序的时候,你将会发现每次按下回车键,count的值就会增加。后台中的线程也会增加count的值,同时以前的线程也会响应用户的输入。这个程序会同时做两件事情。
#include #include
volatile UINT count;
void CountThread() { while(1) { count++; Sleep(100); } }
void main(void) { HANDLE countHandle; DWORD threadID; CHAR retStr[100];
count=0;
// create a thread which // executes the "CountThread" function countHandle=CreateThread(0, 0,(LPTHREAD_START_ROUTINE) CountThread,0, 0, &threadID); if (countHandle==0) cout << "Cannot create thread: " << GetLastError() << endl;
while(1) { cout<< "Press to display the count... "; cin.getline(retStr, 100); cout << "The count is: " << count << endl << endl; } }
|
主线程、后台线程和全局变量之间的关系可用下图表示:

****************图一********************
以上通过使用CreateThread函数来创建线程(该函数的具体描述可参考VC++ 2.0版本的Win32在线帮助或者NT的SDK文档)。CreateThread接受线程函数的名字,该函数会在新的线程中执行。这里的线程函数就是CountThread。线程函数可以选择接受一个4字节的参数。在上面的代码中,线程函数并没有使用任何的参数,不过如果有的话这些参数将会被传送至CreateThread的参数列表中,并且CreateThread会把它回送给线程函数。CreateThread将会返回一个线程ID和句柄给线程。线程ID是用来在系统中唯一确定线程的,并且可接受一些函数,例如AttachThreadInput等。
你可以通过堆栈参数来控制线程堆栈的初始化大小。将堆栈参数设置为0将会令线程堆栈初始化为与它的父线程一样大。堆栈可以根据需要变大,不过增大堆栈会带来系统开销,因此你最好在开始就分配一个适合的大小,这可以通过它使用的局部变量的大小决定。你还可以唤醒一个挂起的线程。在挂起时,该线程将不会占用任何的CPU时间,直到其它线程通过ResumeThread唤醒它。
对于延迟一个线程来说,上面代码中的休眠函数是一个有效的方法。在以前,你可能需要使用循环或者类似的技术来做到一个延迟,不过你也应该知道循环是不可靠的,并且会造成资源的浪费,因为循环也会使用CPU周期,这是不必要的。休眠函数可以延迟一个线程,而无需要花费任何的CPU周期。在休眠中,一个线程是完全挂起的。
你要留意到全局变量count是使用volatile修饰符的。如果你注释掉线程中的Sleep函数,并且除去volatile修饰符,在你按在回车键时,count的值会保持为0。这是由于编译器的优化而造成的一个奇怪现象。例如,对于编译器来说,将可能使用一个寄存器来保存主线程中count变量的值,而忽略第二个线程对该值的修改。volatile修饰符的作用是告诉编译器无需对该变量作任何的优化,即无需要将它放到一个寄存器中,并且该值可在赋值期间被外部改变。你将会发现对于多线程引用的全局变量来说,volatile是一个非常重要的修饰符。