Win32的线程模型

 Win32的线程模型

为了便于以后的探讨,首先看一下Win32的线程模型。 

一个Win32应用程序(或进程)是由一个或多个并发的线程组成的,其中第一个启动的线程称为主线程。 

Win32定义了两种类型的线程,界面线程和工作线程。Win32的每个进程可以有一个或多个界面线程和/或多个工作线程。界面线程拥有一个或多个窗口,拥有一个消息队列和其它属于界面线程的元素。工作线程就是一般的线程,它没有窗口,没有消息队列。 

界面线程通常有一个或几个窗口。当某一个窗口有消息时,界面线程会调用相应的窗口函数(Windows Process)来处理该事件。由于某消息循环由它界面线程处理,同时不必在乎是哪个线程发送消息的,因此,Windows会保证线程间的同步问题。 

对于工作线程,线程间的同步必须由程序员来实现。尽可能避免死锁和竞争出现。 

Win32应用程序模型


Win32应用程序可以分成两大类:控制台程序(console application)和窗口界面程序(windows GUI application)。控制台程序的入口函数是main(),窗口界面程序的入口函数是WinMain()。 

入口函数就是程序的主线程的运行起点。 

这里讨论的开发框架(Framework)是针对窗口界面程序的。 

窗口界面程序通常分成以下几类:SDI, MDI, multi-SDI, 和Dialog应用程序。 

SDI(Single Document Interface)应用程序通常只有一个主窗口(通常是一个框架窗口,Frame Window)。框架窗口包含菜单、工具栏、状态栏和称为视(View)的客户工作区。 

multi-SDI(Multiple Threads SDI)应用程序有框架个主窗口。比如IE浏览器,使用"文件/新建/窗口"命令后,会出现另一个IE窗口。 

MDI(Multiple Document Interface)应用程序有一个主框架窗口,但有多个子框架窗口。每个子窗口都有自己的视(View)。 

Dialog应用程序是基于对话框的。 

通常一个简单的SDI应用程序由两个函数组成。一个是应用程序入口函数WinMain(),另一个是该应用程序窗口的窗口函数。 

程序(主线程)从入口函数开始运行。在该函数中,首先是注册并创建一个主窗口。然后,启动消息循环。消息循环中,根据不同的消息,将消息发送到窗口函数中处理。当消息是退出消息时,该入口函数会退出消息循环,然后结束程序。 

下面是一个最简单的Windows界面应用程序。 

//应用程序入口函数
int APIENTRY WinMain(HINSTANCE hInstance,
      HINSTANCE hPrevInstance,
      LPSTR lpCmdLine,
      int nCmdShow)
{
   MSG msg;

   //1. 注册窗口类
   WNDCLASSEX wcex;
   wcex.cbSize = sizeof(WNDCLASSEX); 
   wcex.style = CS_HREDRAW | CS_VREDRAW;
   wcex.lpfnWndProc = (WNDPROC)WndProc;    //指定窗口函数
   wcex.cbClsExtra = 0;
   wcex.cbWndExtra = 0;
   wcex.hInstance = hInstance;
   wcex.hIcon = LoadIcon(hInstance, (LPCTSTR)IDI_HELLOWORLD);
   wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
   wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
   wcex.lpszMenuName = (LPCSTR)IDC_HELLOWORLD;
   wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance,(LPCTSTR)IDI_SMALL);
   RegisterClassEx(&wcex);
   //2. 创建一个该类型的窗口
   HWND hWnd;
   hWnd = CreateWindow(szWindowClass,szTitle,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, 
CW_USEDEFAULT, 0, NULL, NULL, 
hInstance, NULL);
   if (!hWnd) return FALSE;
   //3. 按nCmdShow所指定的方式显示窗口
   ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
   //4. 启动消息循环,将消息发送给相应的窗口函数
   while (GetMessage(&msg, NULL, 0, 0)) 
   {
      TranslateMessage(&msg);
      DispatchMessage(&msg);
   }
   return msg.wParam;
}
//窗口函数
LRESULT CALLBACK WndProc(HWND hWnd, 
UINT message, 
WPARAM wParam,         
LPARAM lParam)
{
   PAINTSTRUCT ps;
   HDC hdc;
   char* szHello = "Hello, world!";
   switch (message) 
   {
     case WM_PAINT:
      hdc = BeginPaint(hWnd, &ps);
      RECT rt;
      GetClientRect(hWnd, &rt);
      DrawText(hdc, szHello, strlen(szHello),&rt,DT_CENTER);
      EndPaint(hWnd, &ps);
      break;
     case WM_DESTROY:
      PostQuitMessage(0);  //退出应用程序
      break;
     default:
      return DefWindowProc(hWnd, message, wParam, lParam);
     }
    return 0;
  }


上面程序的执行过程如下: 

1、注册窗口类 

在使用CreateWindwo()或CreateWindowEx()创建窗口时,必须提供一个标识窗口类的字符串。该窗口类定义了一些窗口的基本属性。其中一个重要的工作是向操作系统提供窗口函数。该函数是回调函数,用于处理发送给该窗口的消息。 

在上面程序中,仅仅简单的处理了两个消息。一个是向窗口区域画出"Hello world."字符串。另一个是当窗口撤消时,向应用程序发送"退出应用程序"消息。 

2、创建窗口 

3、显示窗口 

4、启动消息循环,分发并处理消息。 

     while (GetMessage(&msg, NULL, 0, 0)) 
     {
      TranslateMessage(&msg);
      DispatchMessage(&msg);
     }


在上述消息循环代码中,调用GetMessage()从线程的消息队列中取出一条消息。如果消息为0(由窗口函数处理"WM_DESTROY"消息时发送的"PostQuitMessage(0)"),会退出消息循环。 

然后调用TranslateMessage()翻译消息。 

翻译后,再调用DispatchMessage()将该消息分发至相应的窗口函数进行处理。 (实际上DispatchMessage()将该消息作为参数调用对应的窗口的窗口函数,这就是分发的实质)。 
发布了7 篇原创文章 · 获赞 0 · 访问量 9232

猜你喜欢

转载自blog.csdn.net/luckeast/article/details/2344147