软件工具与环境

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

(2)非正常结束 一是进程结束(自然也导致线 程的结束)。二是另外的线程以 TerminateThread将它强制结束。 不过TerminateThread少用为好。 4、线程的种类 MFC将线程分为工作者线程 和用户界面线程。
(1)工作者线程(Worker Threads) 工作者线程与用户界面无关, 没有消息循环,一般用来完成后台 工作。 (2)用户界面线程(UI Threads) 用户界面线程与用户界面有关, 具有消息循环来处理界面消息,可 与用户进行交互。
7、程序对MW_DESTROY的标准反 应是调用PostQuitMessage。
8、 PostQuitMessage没有什么操作, 只送出WM_QUIT消息,准备让消息 循环中的GetMessage获取此消息, 结束消息循环。
二、空闲时间的处理 1、空闲时间的概念 所谓空闲时间(idle time)是 指“系统中没有任何消息等待处 理”的时间。例如没有任何程序 使用定时器(timer,它会定时送 来WM_TIMER),使用者也没 有按键盘和鼠标或操作任何外设, 那么系统就处于所谓的空闲时间。
2、Windows9X的抢先式多任务
操作系统能够强迫应用程序把 CPU分享给其它程序。即程序对CPU 的占用时间由系统控制,系统为每个 程序分配一定的CPU时间,当程序的 运行超过规定时间后,系统就会中断 该程序并把CPU控制权让给其它程序。
3、多线程多任务
在Win32系统中,执行一个程序, 必然会产生一个进程;当一个进程建 立后,主线程也产生了。多任务是指 系统可以同时运行多个进程,而每个 进程也可同时执行多个线程。一个程 序可以运行多个线程,每个线程独立 地执行程序代码中的一组语句。
(见图2)
这些核心对象的产生方式(使用 的API)不同,但都会获得一个handle 作为识别;每被使用一次,其对应的 计数值就增1。 核心对象的结束方式相当一致, 调用CloseHandle即可。 Process对象不是用来执行程序代码 的;它只是一个数据结构,系统用它来 管理进程。程序代码的执行是线程的工 作。
2、空闲时间的处理
空闲时间经常发生。后台工作最 适合在空闲时间完成。传统的SDK程 序如果要处理空闲时间,可以用下列 循环取代WinMain中的传统消息循环 (见图1)
原因是PeekMessage和 GetMessage的性质不同:它们都是从 消息队列中获取消息,如果没有消息, 程序的主执行线程(primary thread, 是一个UI执行线程)会被操作系统挂 起。当操作系统再次回来照顾这一执 行线程时,发现消息队列中仍然是空 的,这时两个函数的行为就不同了:
线程是Windows9X/NT系统调 度分配CPU时间的基本单位。进程 至少有一个线程,也可以另外增加 线程。系统为每个线程分配一个 CPU时间片(约20ms),系统不停 地在各个线程之间切换。线程只有 在分配的时间片内才有对CPU的控 制权
1、核心对象
核心对象是系统的一种资源,系 统对象一但产生,任何应用程序都可 以开启并使用该对象。系统给予核心 对象一个计数值作为管理之用。 核心对象包括下列几种:
3、线程的结束
工作者线程的生命就是线程函 数本身,函数一旦return,线程也 就结束。或者线程函数也可以调用 AfxEndThread,结束线程。
用户界面线程因为有消息循 环,必须在消息队列中放一个 WM_QUIT,才能结束线程。
放置消息WM_QUIT的方式 和一般的Win32程序一样,调用 PostQuitMessage即可办到;或者 在线程的任何一个函数中调用 AfxEndThread,也可以结束线程。
2、进程的产生和死亡 执行一个程序,必然会产生一个 进程(process)。最直接的程序执行 方式就是在shell(如Windows 9X的 资源管理器)中用鼠标双击某一个可 执行文件图标(如为app.exe),运 行起来的app进程其实就是shell调用 CreateProcess激活的。整个执行流程 如下:
五、MFC多线程程序设计
1、产生一个工作者线程
由于工作者线程与用户界面无关。 编程时,应该准备一个线程函数,然 后调用AfxBeginThread全局函数: (图11)(例11、例12、例13)
2、产生一个用户界面线程
用户界面线程不能只用一个线程 函数来代表,因为它要处理消息循环。 CWinThread::Run()成员函数中就 有一个消息循环。所以应该先从 CWinThread类中派生一个自己的类, 再调用全局函数AfxBeginThread产生 一个CWinThread类的对象:(图12)
(1)GetMessage会过门不入,于是 操作系统再去照顾其它程序。
(2)PeekMessage会取回控制权, 使程序得以执行一段时间。于是上 述消息循环进入OnIdle函数中。
三、 Windows的多任务 1、Windows3.X的协同式多任务 Windows 3.X都允许同时执行多 个程序。但分享CPU是程序的责任 (即应用程序具有对CPU的控制权)。 如果有一个程序不放弃CPU(许多程 序采用传统的消息循环,而拒绝与其它 程序共享资源),其它程序只有挂起而 无法响应操作。
四、进程与线程 通常用进程(process)表示一个执 行中的程序,并认为它是CPU调度单位。 事实上线程(thread)才是调度单位。 进程是应用程序的运行实例。每个 进程都有自己私有的虚拟地址空间。每 个进程都有一个主线程,但可以建立另 外的线程。进程中的线程是并行执行的, 各线程占用CPU的时间由系统决定。
(9)操作者关闭app主窗口,使 WinMain中的消息循环结束,于是 WinMain结束。
(10)回到Startup code。 (11)回到系统,系统调用 ExitProcess结束进程。
因此通过这种方式执行的所有 Windows程序,都是shell的子进程。 但shell在调用CreateProcess时已经 剪断了父进程与子进程之间的关系, 而使它们成为独立个体。 可以写一个程序,专门用来激活 其它的程序。关键在于我们能否正确 运用具有众多参数的API函数 CreateProcess(图3)
4、程序不断进行上述2和3的操作。 5、当操作者按下系统菜单中的Close 命令项时,系统送出WM_CLOSE。 通常程序的窗口函数不拦截此消息, 于是DefWindowProc处理它。 6、DefWindowProc收到WM_CLOSE后 调用DestroyWindow把窗口清除。 DefWindowProc本身又会送出 WM_DESTROY。
这种方法对系统效率会造成冲击。 因此,绝对不要在Win32中使用这种 循环的方法。(例8) 3)Win32提供一种等待一个对象的 方法:WaitForSingleObject( )函数 (图9)(例9) 4)Win32也提供一种同时等待一个以 上对象的函数 WaitForMultiplebject( ) (图10)(例10)
前面使用了两种等待方法。 1)第一种方法是Win32 Sleep( )函数 这个函数要求操作系统暂时中止 线程的动作,直到经过某个指定的时 间后才能恢复。实际上,程序员不可 能知道具体应该要等待多少时间。
2)第二种方法是使用循环等待,不 断调用GetExitCodeThread( ),直到 其结果不再是STILL_ACTIVE。
3、一个线程的产生与死亡 执行程序代码是线程的工作。当 一个进程建立后,主线程也产生了。 所以每一个Windows程序一开始就有 一个线程。我们可以调用 CreateThread产生额外的线程,系统 会帮我们完成下列事情: (1)配置线程对象,其handle将成为 CreateThread的返回值。
如果一个进程要结束自己,只要 调用: VOID ExitProcess(UINT fuExitCode)
如果说一个进程要结束另一个进 程,可以使用:(图4) 显然,只要有某个进程的handle, 就可以结束它。
前面曾提过剪断父子进程关系 的概念,只要我们在父进程结束前, 把它所开启的核心对象(如子进程、 线程对象等)用CloseHandle关闭, 就可以实现此目的,操作系统会自 动把对象的计数值减1,表示与此核 心对象不再有任何关系(图5)。如 果计数值为0,对象会自动被操作系 统摧毁。
(2)设定计数值为1。 (3)配置线程的context。 (4)保存线程的堆栈。 (5)将context中的堆栈指针和指令 指针设定妥当。 如果要在程序中产生一个新线程, 调用CreateThread(图6)即可。 (例1、例2、例3)
当完成工作后,应该调用 CloseHandle释放核心对象(图7)。 (例4) 使用“线程核心对象”的线程会 使核心对象开启。因此线程对象的默 认计数值为2。当调用CloseHandle() 时,计数值减1;当线程对象结束时, 计数值再减1。只有当这两件事都有发 生了,对象才会被真正清除。
软件工具与环境
第二章
多任务与多线程编程
一、Windows程序的生与死
在了解Windows程序的架构以及 它与Windows系统之间的关系后,对 Windows消息种类以及产生时机的透 彻了解,正是程序设计的关键。下面 以窗口的产生与死亡,说明消息的产 生与传递,以及应用程序的生与死。
1、程序初始化过程中调用 CreateWindow,为程序建立了一个窗 口,作为程序的屏幕舞台。 CreateWindow产生窗口之后会送出 WM_CREATE直接给窗口函数,后者于 是可以在此时做些初始化操作(例如 配置内存、打开文件、读初始数据等。
线程的结束有两种情况:
(1)一种是正常结束
这种情况是线程函数结束退出, 线程也就自然结束了(例5 )。这时 系统会调用ExitThread(图8)做些 清理工作;当然线程自己也可以自行 调用此函数来结束自己。(例6)
在下面的程序中将CloseHandle 函数与GetExitCodeThread函数的关 系作了调整:CloseHandle的调用操 作被移到了GetExitCodeThread的前 面,目的是使GetExitCodeThread的 调用失败(例7)。
(1)shell调用CreateProcess激活 app.exe (2)系统产生一个进程核心对象,计 数值为1。 (3)系统为地 址空间中,包括app.exe的程序、数据, 以及所需的动态链接库(dlls).
(5)系统为此进程建立一个线程, 称为主线程(primary thread)。 线程才是CPU时间的分配对象。 (6)系统调用CRuntime函数库的 Startup code。 (7)Startup code调用app程序的 WinMain函数。 (8)app程序开始运行。
2、在程序活着的过程中,不断以 GetMessage从消息队列中获取消息。 如果这个消息是WM_QUIT, GetMessage会返回0而结束while循环, 进而结束整个程序。 3、DispatchMessage通过Windows USER模块的协助和监督,把消息 分发给窗口函数。消息将在该处被 判别并处理。
相关文档
最新文档