⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 11.txt

📁 VC++技术内幕精讲
💻 TXT
📖 第 1 页 / 共 2 页
字号:
第十一章:Winsows消息处理和多线程编程


一)Winsows消息处理

1,单线程:程序代码只有一条执行路径。

2,单线程程序消息处理过程:
MSG message;
while(::GetMessage(&message,NULL,0,0))
{
::TranslateMessage(&message);//翻译如wm_char消息
::DispatchMessage(&message);//把消息分发给指定窗口的回调函数
}
说明:
1)os决定哪个消息属于我们的程序,当一个消息要处理的时候,用GetMessage函数返回该消息。
2)如果没有属于我们程序的消息发出,则我们的程序被挂起,而其它的程序可以运行;当属于我们程序的消息到达,我们的程序被唤醒

3,改造2中的单线程消息处理过程:
问题一:某个消息控制函数很“笨重”,消耗CPU时间过久。
问题二:DispatchMessage函数要等到该笨重消息控制函数返回后才能返回。在该笨重消息控制函数返回之前DispatchMessage不处理(分发)任何消息。
解决方法:使用PeekMessage函数使占用CPU时间过久的消息控制函数每隔一段时间交出控制一次。(在占CPU时间过久的控制函数中利用PostMessage发送
代码如下:
MSG message;
while(::PeekMessage(&message,NULL,0,0,PM_REMOVE))
{
::TranslateMessage(&message);//翻译如wm_char消息
::DispatchMessage(&message);//把消息分发给指定窗口的回调函数
}
说明:
//The PeekMessage function checks a thread message queue for a message and places the message (if any) in the specified structure. 
简要说明:
1)BOOL PeekMessage(
  LPMSG lpMsg,         // pointer to structure for message
  HWND hWnd,           // handle to window
  UINT wMsgFilterMin,  // first message
  UINT wMsgFilterMax,  // last message
  UINT wRemoveMsg      // removal flags
);
//If a message is available, return nonzero,otherwise return 0;
//Unlike the GetMessage function, the PeekMessage function does not wait for a message to be placed in the queue before returning.
//PeekMessage retrieves only messages associated with the window identified by the hWnd parameter or any of its children as specified by the IsChild function, and within the range of message values given by the wMsgFilterMin and wMsgFilterMax parameters. 
//If hWnd is NULL, PeekMessage retrieves messages for any window that belongs to the current thread making the call.
//If hWnd is –1, PeekMessage only returns messages with a hWnd value of NULL, as posted by the PostThreadMessage function. 
//If wMsgFilterMin and wMsgFilterMax are both zero, PeekMessage returns all available messages (that is, no range filtering is performed). 
//PeekMessage does not retrieve messages for windows that belong to other threads.

2)BOOL GetMessage(
  LPMSG lpMsg,         // address of structure with message
  HWND hWnd,           // handle of window
  UINT wMsgFilterMin,  // first message
  UINT wMsgFilterMax   // last message
);
//GetMessage does not retrieve messages for windows that belong to other threads or applications. 
//

4,计时器独立于CPU时钟速度。
1)计时器的使用:用一个时间间隔参数调用CWnd::SetTimer函数,然后再用ClassWizard为WM_TIMER添加消息控制函数。
2)一旦调用CWnd::SetTimer启动了计时器,则WM_TIMER消息会被持续发送到指定的窗口,直至调用CWnd::KillTimer函数或计时器窗口被取消为止。
3)由于WINDOWS非实时OS,如果时间间隔少于100毫秒,计时器可能不准。
4)OS发送计时器消息的时候,如果队列里已经有了计时器消息,则不会把同样的计时器消息放进消息队列里。
说明:
1)CWnd::SetTimer
UINT SetTimer( UINT nIDEvent, UINT nElapse, void (CALLBACK EXPORT* lpfnTimer)(HWND, UINT, UINT, DWORD) );
//Return The timer identifier of the new timer if the function is successful. An application passes this value to the KillTimer member function to kill the timer. Nonzero if successful; otherwise 0.
//nIDEvent:Specifies a nonzero timer identifier.
//nElapse:Specifies the time-out value, in milliseconds.
//lpfnTimer:Specifies the address of the application-supplied TimerProc callback function that processes the WM_TIMER messages. If this parameter is NULL, the WM_TIMER messages are placed in the application’s message queue and handled by the CWnd object.
//CWnd::SetTimer Installs a system timer. A time-out value is specified, and every time a time-out occurs, the system posts aWM_TIMER message to the installing application’s message queue or passes the message to an application-defined TimerProc callback function. 
2)CWnd::KillTimer
BOOL KillTimer( int nIDEvent );
//Return value:Return nozero if the event is killed.It is 0 if the KillTimer member function could not find the specified timer event.
//CWnd::KillTimer Kills the timer event identified by nIDEvent from the earlier call to SetTimer. Any pending WM_TIMER messages associated with the timer are removed from the message queue.


5,在引入多线程编程之前,WINDOWS程序员曾使用空状态处理来完成一些后台任务。(这里是OnIdle函数)
1)应用程序框架在框架消息处理循环中调用CWinApp::OnIdle(虚函数),可以重载它来处理后台任务。通常,一但OnIdle函数完成了它的工作,就要等到下次应用程序消息队列空了后才被调用。基类的OnIdle会更新工具栏按钮和状态栏指示器,并清除各种临时对象指针。
2)重载OnIdle函数可以用来更新用户界面,很有实际意义。(注:在重载OnIdle函数中一定要调用基类的OnIdle函数哦)
3)如果用户运行在一个模式对话框或正在使用菜单,则这时OnIdle函数不被调用。但我们可以在框架类中添加WM_ENTERIDLE消息控制函数来在上叙情况下使用后台处理。(注意,这里是在框架类中添加,不是在视图类中。弹出式对话框中是属于应用程序主框架窗口。)

///////
///////

二,多线程编程:

1,一些概念:
1)一个进程就是一个运行的程序,进程具有独立的内存、文件句柄和其它系统资源。
2)一个独立的进程可以包含多条执行路径,称为线程。线程有OS管理,每个线程有自己的堆栈。
3)大多数情况下,进程的所有代码和数据空间被进程内所有的线程所共享。
4)Windows提供两中线程:辅助线程 和 用户界面线程。mfc对两种线程都支持。
5)一个用户界面线程有窗口,因而有自己的消息循环;辅助线程没有窗口,因而不需要消息处理。

2,启动辅助线程:
准备工作:写一个全局函数。格式:UINT MyControllingFunction( LPVOID pParam );
启动辅助线程:使用AfxBeginThread函数为全局函数MyControllingFunction创建线程。
说明一:
MFC 通过参数重载提供两个版本的 AfxBeginThread:一个用于用户界面线程,另一个用于辅助线程。
//用户界面线程通常用于处理用户输入和响应用户事件,这些行为独立于执行该应用程序其他部分的线程。已经创建并启动主应用程序线程(在 CWinApp 导出的类中提供)。
//辅助线程通常用于处理后台任务,用户不必等待就可以继续使用应用程序。重新计算和后台打印等任务是很好的辅助线程示例。
说明二:
创建用户界面线程比创建辅助复杂(需要重写一些相关的函数),这里只笔记创建辅助线程一些笔记。
1)AfxBeginThread 
CWinThread* AfxBeginThread( AFX_THREADPROC pfnThreadProc, LPVOID pParam, int nPriority = THREAD_PRIORITY_NORMAL, UINT nStackSize = 0, DWORD dwCreateFlags = 0, LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL );
//Return Value:Pointer to the newly created thread object.
//pfnThreadProc:Points to the controlling function for the worker thread. Cannot be NULL. This function must be declared as follows:    UINT MyControllingFunction( LPVOID pParam );
//pParam:Parameter to be passed to the controlling function as shown in the parameter to the function declaration in pfnThreadProc.
//nPriority:The desired priority(优先权) of the thread. If 0, the same priority as the creating thread will be used. For a full list and description of the available priorities, seeSetThreadPriority in the Win32 Programmer’s Reference.
//nStackSize:Specifies the size in bytes of the stack for the new thread. If 0, the stack size defaults to the same size stack as the creating thread.
//dwCreateFlags:Specifies an additional flag that controls the creation of the thread. This flag can contain one of two values: 
[CREATE_SUSPENDED]   Start the thread with a suspend count of one. The thread will not execute until ResumeThread is called.
[ 0  ]  Start the thread immediately after creation. 
//lpSecurityAttrs:Points to a SECURITY_ATTRIBUTES structure that specifies the security attributes for the thread. If NULL, the same security attributes as the creating thread will be used. 
//Remarks:
Call this function to create a new thread. The first form of AfxBeginThread creates a worker thread. The second form creates a user-interface thread. 
To end the thread, call AfxEndThread from within the thread, or return from the controlling function of the worker thread.
2)挂起线程:
CWinThread::SuspendThread

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -