MFC【17-3】线程和线程同步化

17.3小知识点

17.3.1消息泵

编写一个应用程序,让它响应某菜单命令,画几千个椭圆。

 1 void CMFC线程View::OnStartDrawing(void)
 2 {
 3     m_bQuit=FALSE;
 4     for(int i=0;i<NUMELLIPSES&&!m_bQuit;i++)
 5     {
 6         DrawRandomEllipse();
 7         if(!PeekAndPump())
 8             break;
 9     }
10 }
11
12
13 void CMFC线程View::OnStopDrawing(void)
14 {
15     m_bQuit=TRUE;
16 }
17
18
19 bool CMFC线程View::PeekAndPump(void)
20 {
21     MSG msg;
22     while(::PeekMessage(&msg,NULL,0,0,PM_NOREMOVE)){
23         if(!AfxGetApp()->PumpMessage()){
24             ::PostQuitMessage(0);
25             return FALSE;
26         }
27     }
28     LONG 1Idle=0;
29     while(AfxGetApp()->OnIdle(1Idle++));
30     return TRUE
31 }

PeekAndPump在一个消息循环中定制另一个消息循环。它在OnStartDrawing中for语句的循环终点处被调用。如果::PeekMessage指示队列中有消息等待,则PeekAndPump首先调用CWinThread::PumpMessage提取消息和分派消息。如果PumpMessage返回0,则表示提取和分派的最后一个消息是WM_QUIT消息。而因为只有用“主”消息循环提取WM_QUIT消息,应用程序才能结束,所以该消息要求特殊处理。因此如果PumpMessage返回0,PeekAndPump就会把另一个WM_QUIT消息发往队列;如果PeekAndPump返回0,就会把另一个WM_QUIT消息发往队列;如果PeekAndPump返回0,OnStartDrawing中的for语句循环就会失败。如果WM_QUIT消息不提示提前退出,那么通过在返回之前调用应用程序对象的OnIdle函数,PeekAndPump就可以模仿主程序的闲置机制。

17.3.2执行其他进程

Win32执行进程。下列语句执行c:\\WINDOWS\Notepad.exe.

 1     STARTUPINFO si;
 2     ::ZeroMemory(&si,sizeof(STARTUPINFO));
 3     si.cb=sizeof(STARTUPINFO);
 4     PROCESS_INFORMATION pi;
 5
 6     if(::CreateProcess(NULL,_T("C:\\Windows\\Notepard"),NULL,NULL,FALSE,NORMAL_PRIORITY_CLASS,
 7         NULL,NULL,&si,&pi)){
 8             ::CloseHandle(pi.hThread);
 9             ::CloseHandle(pi.hProcess);
10     }

::CreateProcess是一个通用函数,它获取可执行文件的名字(和路径),然后加载并执行他,如果可执行文件名中的驱动器和目录名被省略,则系统自动在Windows目录,Windows系统目录,当前路径下的所有目录和选中的其他位置中搜索该文件。文件名也可以包含命令行参数,如:

“C:\\Windows\\Notepad C: \\ Windows\\ Desktop\\Ideas.txt"

::CreatProcess将进程的关键信息填充在PROCESS_INFORMATION结构中。相关信息包括:进程句柄(hProcess)和进程中主线程的句柄(hThread)。在进程启动后,要用::CloseHandle关闭这些句柄。如果CreateProcess返回非零值,则意味着进程启动成功。因为Win32是一部启动、一部执行的,所以CreateProcess不必等到进程结束后再返回。如果您希望启动另一个进程,并暂停当前进程知道该进程启动的进程结束,则您可以对该进程句柄调用::WaitForSingleObject

    STARTUPINFO si;
    ::ZeroMemory(&si,sizeof(STARTUPINFO));
    si.cb=sizeof(STARTUPINFO);
    PROCESS_INFORMATION pi;

    if(::CreateProcess(NULL,_T("C:\\Windows\\Notepard"),NULL,NULL,FALSE,NORMAL_PRIORITY_CLASS,
        NULL,NULL,&si,&pi)){
            ::CloseHandle(pi.hThread);
            ::WaitForSingleObject(pi.hProcess,INFINITE);
            ::CloseHandle(pi.hProcess);
    }

进程和线程一样都有退出代码。如果::WaitForSingleObject没有返回WAIT_FAILED,则可以调用::GetExitCodeProcess获取进程的退出代码。

  有时需要启动进程并等待足够长的时间后,才能确保进程已开始并相应用户输入。例如:如果进程A启动进程B,而进程B又创建了一个窗口,这是,如果进程A要给窗口发送消息,他就不得不等到CreateProcess返回,留给进程B足够的时间创建窗口并开始处理消息。通过Win32::WaitForInputIdle函数可以解决这个问题。

    STARTUPINFO si;
    ::ZeroMemory(&si,sizeof(STARTUPINFO));
    si.cb=sizeof(STARTUPINFO);
    PROCESS_INFORMATION pi;

    if(::CreateProcess(NULL,_T("C:\\Windows\\Notepard"),NULL,NULL,FALSE,NORMAL_PRIORITY_CLASS,
        NULL,NULL,&si,&pi)){
            ::CloseHandle(pi.hThread);
            ::WaitForInputIdle(pi.hProcess,INFINITE);
            ::CloseHandle(pi.hProcess);
    }

17.3.3文件改变通知

::WaitForSingleObject的HANDLE参数可以是“文件改变通知句柄”。Win32 API包含一个函数::FindFirstChangeNotification,只要给定目录或他的子目录发生了变化,例如文件被重命名或删除,或创建了一个新目录,该函数都能返回一个句柄,通过该句柄您可以启动一个被阻塞的线程。

如果想改善11章中的Wanderer应用程序,使文件系统的而变化难呢过立刻反应在左面或右面的窗格中。为此,最有效的方法是启动一个后台线程,并使它在一个或多个文件改变通知句柄上处于阻塞状态。下面是用来监视驱动器C:的线程的线程函数:

UINT ThreadFunc(LPVOID pParam)
{
    HWND hwnd=(HWND)pParam;//Window to notify
    HANDLE hChange = ::FindFirstChangeNotification(_T("C:\\"),
        TRUE,FILE_NOTIFY_CHANGE_FILE_NAME);// FILE_NOTIFY_CHANGE_DIR_NAME);
    if(hChange==INVALID_HANDLE_VALUE){
    TRACE(_T("Error:FindFirstChangeNotification failed\n"));
    return(UINT) -1;
}
    while(){
        ::WaitForSingleObject(hChange,INFINITE);
        ::PostMessage(hwnd,WM_USER_CHANGE_NOTIFY,0,2);
        ::FindNextChangeNotification(hChange);//Reset
    }
    ::FindCloseChangeNotification(hChange);
    return 0;
}
时间: 2024-12-26 18:26:08

MFC【17-3】线程和线程同步化的相关文章

MFC【17-1】线程和线程同步化

17.1线程 对于Windows来说所有的线程都是一样的,但MFC却把线程区分为两种类型:User Interface(UI) threads(用户界面(UI)线程)和Worker threads(工作者线程). 两种线程的不同之处在于UI线程具有消息循环而工作者线程没有.UI线程可以创建窗口并处理发送给这些窗口的消息.工作者线程执行后台任务. 17.1.1创建工作者线程 AfxBeginThread定义了两个版本:一个启动UI线程,另一个启动过作者线程 CWinThread*pThread=A

Day 36(07/17)进程与线程

一 进程与线程的概念 1.1 进程 考虑一个场景:浏览器,网易云音乐以及notepad++ 三个软件只能顺序执行是怎样一种场景呢?另外,假如有两个程序A和B,程序A在执行到一半的过程中,需要读取大量的数据输入(I/O操作),而此时CPU只能静静地等待任务A读取完数据才能继续执行,这样就白白浪费了CPU资源.你是不是已经想到在程序A读取数据的过程中,让程序B去执行,当程序A读取完数据之后,让程序B暂停.聪明,这当然没问题,但这里有一个关键词:切换. 既然是切换,那么这就涉及到了状态的保存,状态的恢

基础学习day11--多线程一线程的创建,运行,同步和锁

1.1.进程和线程 进程:一个应用程序一般都是一个进程,正在进行的程序 每一个进程最少都有一个线程,都有一个执行顺序,该顺序是一个执行路径或者一个控制单元 线程:进程中一个独立的控制单元,线程控制着进程的执行. windows中的任务管理器,可以查看进程,linux下通过ps命令 线程是进程的最小单位 线程依赖于进程 线程随着进程的创建和创建,随着进程的结束而消亡 如迅雷:可以同时开启多个下载,就是多线程 多个程序同时执行,时CPU在很快的切换,看上去是同时执行,实际上是在CPU在切换执行. 多

猎豹MFC--进程和线程--创建线程AfxBeginThread() SetDlgItemInt()线程暂停继续终止

增加一按钮  双击: SPY++查看  进程下面的线程: 另一个线程函数: 定义一个指针变量: 在构造函数中初始化: 暂停线程: 线程继续: 定义布尔变量 记录 线程有没有在运行: 初始化该变量: 修改县城函数demoA: 对话框添加按钮,双击该按钮: 增加一个线程函数: 实现线程函数: 增加第2个按钮  掉用第二个线程函数:' 按了第一个按钮立马按第二个按钮时  也就是当两个线程并发执行时就会出错: 以上是线程同步的四种方法,是MFC的C++类 定义指针:指向临界区对象: 在构造函数中 创建临

Java线程:线程状态的转换

Java线程:线程状态的转换 一.线程状态 线程的状态转换是线程控制的基础.线程状态总的可分为五大状态:分别是生.死.可运行.运行.等待/阻塞.用一个图来描述如下: 1.新状态:线程对象已经创建,还没有在其上调用start()方法. 2.可运行状态:当线程有资格运行,但调度程序还没有把它选定为运行线程时线程所处的状态.当start()方法调用时,线程首先进入可运行状态.在线程运行之后或者从阻塞.等待或睡眠状态回来后,也返回到可运行状态. 3.运行状态:线程调度程序从可运行池中选择一个线程作为当前

Java - &quot;JUC线程池&quot; 线程状态与拒绝策略源码分析

Java多线程系列--"JUC线程池"04之 线程池原理(三) 本章介绍线程池的生命周期.在"Java多线程系列--"基础篇"01之 基本概念"中,我们介绍过,线程有5种状态:新建状态,就绪状态,运行状态,阻塞状态,死亡状态.线程池也有5种状态:然而,线程池不同于线程,线程池的5种状态是:Running, SHUTDOWN, STOP, TIDYING, TERMINATED. 线程池状态定义代码如下: private final AtomicI

基础学习day12--多线程一线程之间的通信和常用方法

一.线程之间的通信 1.1.线程之间的通信方法 多个线程在处理统一资源,但是任务却不同,这时候就需要线程间通信.    等待/唤醒机制涉及的方法:    1. wait():让线程处于冻结状态,被wait的线程会被存储到线程池中.    2. notify():唤醒线程池中的一个线程(任何一个都有可能).    3. notifyAll():唤醒线程池中的所有线程.  备注    1.这些方法都必须定义在同步中,因为这些方法是用于操作线程状态的方法.    2.必须要明确到底操作的是哪个锁上的线

C#中的线程(二) 线程同步基础

1.同步要领 下面的表格列展了.NET对协调或同步线程动作的可用的工具:                       简易阻止方法 构成 目的 Sleep 阻止给定的时间周期 Join 等待另一个线程完成                       锁系统 构成 目的 跨进程? 速度 lock 确保只有一个线程访问某个资源或某段代码. 否 快 Mutex 确保只有一个线程访问某个资源或某段代码.可被用于防止一个程序的多个实例同时运行. 是 中等 Semaphore 确保不超过指定数目的线程访问某

java线程和线程池的使用

java线程和线程池 一.创建多线程的方式 java多线程很常见,如何使用多线程,如何创建线程,java中有两种方式,第一种是让自己的类实现Runnable接口,第二种是让自己的类继承Thread类.其实Thread类自己也是实现了Runnable接口.具体使用实例如下: 1.通过实现Runnable接口方式 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public class MyThread1 implements Runnab