windows多线程编程简介(2)

来源:互联网 发布:ps软件什么好 编辑:程序博客网 时间:2024/06/07 20:33

当使用CreateProcess调用时,系统将创建一个进程和一个主线程。CreateThread将在主线程的基础上创建一个新线程,大致做如下步骤:
  1在内核对象中分配一个线程标识/句柄,可供管理,由CreateThread返回
  2把线程退出码置为STILL_ACTIVE,把线程挂起计数置1
  3分配context结构
  4分配两页的物理存储以准备栈,保护页设置为PAGE_READWRITE,第2页设为PAGE_GUARD
  5lpStartAddr和lpvThread值被放在栈顶,使它们成为传送给StartOfThread的参数
  6把context结构的栈指针指向栈顶(第5步)指令指针指向startOfThread函数


当你创建一个线程时,其实那个线程是一个循环。这样就带来了一个问题,在那个死循环里要找到合适的条件退出那个死循环,那么是怎么样实现它的呢?在Windows里往往是采用事件的方式,当然还可以采用其它的方式。在这里先介绍采用事件的方式来通知从线程运行函数退出来,它的实现原理是这样,在那个死循环里不断地使用WaitForSingleObject函数来检查事件是否满足,如果满足就退出线程,不满足就继续运行。当在线程里运行阻塞的函数时,就需要在退出线程时,先要把阻塞状态变成非阻塞状态,比如使用一个线程去接收网络数据,同时使用阻塞的SOCKET时,那么要先关闭SOCKET,再发送事件信号,才可以退出线程的。


事件对象就像一个开关:它只有两种状态---开和关。当一个事件处于”开”状态,我们称其为”有信号”否则称为”无信号”。可以在一个线程的执行函数中创建一个事件对象,然后观察它的状态,如果是”无信号”就让该线程睡眠,这样该线程占用的CPU时间就比较少。


产生事件对象的函数如下:  

HANDLE  CreateEvent(        LPSECURITY_ATTRIBUTES     lpEventAttributes,             BOOL     bManualReset,                                                      BOOL     bInitialState,                                                       LPCTSTR     lpName                                                          ); 
该函数创建一个Event同步对象,如果CreateEvent调用成功的话,会返回新生成的对象的句柄,否则返回NULL。


参数说明:
lpEventAttributes          // 一般为NULL  
bManualReset              //创建的Event是自动复位还是人工复位.如果true,人工复位,  一旦该Event被设置为有信号,则它一直会等到ResetEvent()API被调用时才会恢复 为无信号.    如果为false,Event被设置为有信号,则当有一个wait到它的Thread时,  该Event就会自动复位,变成无信号.   如果想在每次调用WaitForSingleObject后让WINDOWS为您自动地把事件地状态恢复为”无信号”状态,必须把该参数设为FALSE,否则,您必须每次调用ResetEvent函数来清除事件的信号。

bInitialState                  //初始状态,true,有信号,false无信号   
lpName                        //事件对象的名称。您在OpenEvent函数中可能使用。


补充说明:
一个Event被创建以后,可以:

用OpenEvent()API来获得它的Handle,用CloseHandle()来关闭它

用SetEvent()或PulseEvent()来设置它使其有信号,用ResetEvent()来使其无信号

用WaitForSingleObject()或WaitForMultipleObjects()来等待其变为有信号.  





举例说明(一道面试题):

/***----------------Demo two----------------***//*编写一个程序,开启3个线程,这3个线程的ID分别为A、B、C,每个线程将自己的ID在屏幕上打印10遍,要求输出结果必须按ABC的顺序显示;如:ABCABC….依次递推解:依然是多线程同步的问题,A做完,B做,B做完C,依次循环,使用事件来完成。*/#include <Windows.h>#include <iostream>using namespace std;HANDLE glo_threadEvent[3];intglo_eventIndex = 0;DWORD WINAPI ThreadFunc(void *p){int param = (int)p;char threadName = 'A' + param;for(int index = 0; index < 10; index++){//线程ABC分别等待事件0,1,2//又因为初始glo_threadEvent[0]已经被设置为有信号了,所以第一个线程首先被执行//在事件对象生成后,必须调用WaitForSingleObject来让线程进入等待状态WaitForSingleObject(glo_threadEvent[param], INFINITE);printf("the thread is %c\n", threadName);//使其无信号ResetEvent(glo_threadEvent[glo_eventIndex]);//设置下一个事件为有信号,则执行下一个线程glo_eventIndex = (glo_eventIndex + 1) % 3;SetEvent(glo_threadEvent[glo_eventIndex]);}return 0;}int main(int argc, char* argv[]){for(int index = 0; index < 3; index++){//为每个线程句柄创建一个事件//Creates or opens a named or unnamed event object.glo_threadEvent[index] = CreateEvent(NULL, false, false, NULL);}//首先设置第一个事件为有信号//Sets the specified event object to the signaled state.SetEvent(glo_threadEvent[0]);HANDLE hThread[3];for(int index = 0; index < 3; index++){//为每个线程创建一个执行函数并带入函数参数(void *)indexhThread[index] = (HANDLE)CreateThread(NULL, 0, ThreadFunc, (void *)index, 0 ,NULL);}//设置等待类型为TRUE,有信号情况下执行WaitForMultipleObjects(3, hThread, TRUE, INFINITE);cout<<"run is end ,plz press any key to exit..."<<endl;char c = getchar();CloseHandle(glo_threadEvent);return 0;}


0 0
原创粉丝点击