30、深入浅出MFC学习笔记,多线程

摘要:
调度器基于每个执行线程的优先级。由于消息loop_QUIT,UI执行线程必须将WM放入消息队列中以结束执行线程。参考[1]MFC

一、基本概念

1、模块:一段可执行的程序(包括EXEDLL),其程序代码、数据、资源被加载到内存中,由系统建置一个数据结构来管理它,就是一个模块。这里所说的数据结构,名为Module DatabaseMDB),其实就是PE格式中的PE表头,可以从WINNT.H 档中找到一个IMAGE_NT_HEADER 结构,就是它。

2、进程:就是一大堆拥有权(ownership)的集合。进程拥有地址空间(由memory context决定)、动态配置而来的内存、文件、执行线程、一系列的模块。操作系统使用一个所谓的Process DatabasePDB)数据结构,来记录(管理)它所拥有的一切。

3、线程:系统以一个特定的数据结构(Thread DatabaseTDB)记录执行线程的所有相关资料,包括执行线程局部储存空间(Thread Local StorageTLS)、消

息队列、handle表格、地址空间(Memory Context )等。

进程主要表达「拥有权」的观念,执行线程则主要表达模块中的程序代码的「执行事实」。

4CPU调度单位是执行线程。调度器据以排序的,是每个执行线程的优先权。

5、一般,timeslice20milliseconds

6PDB连接模块示例

wps_clip_image-28024

7、当Windows 加载器将程序加载内存中,KERNEL32挖出一些内存,构造出一个PDB、一个TDB、一个以上的MDBs(视此程序使用到多少DLL而定)。针对TDB,操作系统又要产生出memory context(就是在操作系统书籍中提到的那些所谓page tables)、消息队列、handle表格、环境数据结(EDB)。当这些系统内部数据结构都构造完毕,指令指位器(Instruction Pointer)移到程序的进入点,才开始程序的执行。

8、会被冻结,表示这个执行线程「要去抓取消息,而执行线程所附带的消息队列中却没有消息」。

    冻结有两种方法:一种是SuspendThread,另外一种是暂时冻结Sleep

9、线程上下文:狭义来讲是指一组缓存器值(包括指令指位器IP)。

10Worker ThreadsUI Threads

    从Windows 操作系统的角度来看,执行线程并未分类。但从MFC的角度看,则把执行线程划分为和使用者接口无关的worker threads,以及和使用者接口

UI)有关的UI threads

    基本上,当我们以::CreateThread 产生一个执行线程,并指定一个执行线程函数,它就是一个worker thread,除非在它的生命中接触到了输入消息-这时候它应该有一个消息循环,以抓取消息,于是该执行线程摇身一变而为UI thread

注意,执行线程本来就带有消息队列。而如果执行线程程序代码中带有一个消息循环,就称为UI thread

11、用多线程的时机

把所有UIUser Interface)动作都集中在主执行线程中,其它的「纯种运算工作」考虑交给worker threads

12、创建多线程

应该先产生一个CWinThread对象,再调用其成员函数CreateThread或全域函数AfxBeginThread将执行线程产生出来。因为CWinThread::CreateThread AfxBeginThread不只是::CreateThread 的一层包装,更做了一些application framework所需的内部数据初始化工作,并确保正确的C runtime library版本。

1)建立Worker Threads

    利用函数CreateThread或全域函数AfxBeginThread去做。

示例程序

CWinThread* pThread = AfxBeginThread(ThreadFunc, &Param);
...
UINT ThreadFunc (LPVOID pParam)
{
...
}

2)建立UI Threads

产生CWinThread 对象,为了借助其中的消息循环,CWinThread::Run

示例程序

class CMyThread : public CWinThread
{
DECLARE_DYNCREATE(CMyThread)
public:
void BOOL InitInstance();
};
IMPLEMENT_DYNCREATE(CMyThread, CWinThread)
BOOL CMyThread::InitInstance()
{
...
}
CWinThread *pThread = AfxBeginThread(RUNTIME_CLASS(CMyThread));

3)线程的结束

    对于worker thread,执行线程函数return,执行线程也就结束了。或者执行线程函数也可以调用AfxEndThread,结束一个执行线程。

    UI执行线程因为有消息循环的关系,必须在消息队列中放一个WM_QUIT,才能结束执行线程。放置的方式和一般Win32程序一样,调用::PostQuitMessage 即可办到。亦或者,在执行线程的任何一个函数中调用AfxEndThread,也可以结束执行线程。

    不论worker thread UI thread,都需要一个CWinThread 对象,当执行线程结束,记得把该对象释放掉(利用delete)。

参考

[1] 深入浅出MFC

免责声明:文章转载自《30、深入浅出MFC学习笔记,多线程》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇使用C#实现ADSL自动拨号JavaScript-Tool-富文本:UEditor下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Java读写锁

读写锁在同一时刻可以允许多个读线程访问,但是在写线程访问时,所有的读线程和其他写线程均被阻塞。读写锁维护了一对锁,一个读锁和一个写锁,通过分离读锁和写锁,使得并发性相比一般的排它锁有了很大的提升。 一般情况下,读写锁的性能都会比排它锁好,因为大多数场景读是多于写的。在读多于写的情况下,读写锁能够提供比排它锁更好的并发性和吞吐量。Java并发包提供读写锁的实...

Java_如何等待子线程执行结束

工作中往往会遇到异步去执行某段逻辑, 然后先处理其他事情, 处理完后再把那段逻辑的处理结果进行汇总的产景, 这时候就需要使用线程了. 一个线程启动之后, 是异步的去执行需要执行的内容的, 不会影响主线程的流程,  往往需要让主线程指定后, 等待子线程的完成. 这里有几种方式. 站在 主线程的角度, 我们可以分为主动式和被动式. 主动式指主线主动去检测某个标...

android 在子线程中使用handler更新界面

1. 在子线程中创建一个handler对象,让这个handler对象获取主线程的looper,这样才能把这个handler中的消息发送到ui线程的消息队列中 下面这个界面当点击updateui按钮就会创建一个对象然后调用它的更新图片和文字的方法,这两个设置方法在子线程中执行。 在更新界面的对象的类中创建一个handler对象,在初始化的时候给他赋值为Lo...

【转】编写高质量代码改善C#程序的157个建议——建议85:Task中的异常处理

建议85:Task中的异常处理在任何时候,异常处理都是非常重要的一个环节。多线程与并行编程中尤其是这样。如果不处理这些后台任务中的异常,应用程序将会莫名其妙的退出。处理那些不是主线程(如果是窗体程序,那就是UI主线程)产生的异常,最终的办法都是将其包装到主线程上。在任务并行库中,如果对任务运行Wait、WaitAny、WaitAll等方法,或者求Resul...

MFC常见问题解惑

MFC类的分类 1Root: CObject :CObject2Application Architecture Classes:CWinApp/CFrameWnd/... 3Window, Dialog, and Control Classes:CWnd/CDialog/...4Drawing and Printing Classes :CGdiObje...

浅谈java中线程和操作系统线程

  在聊线程之前,我们先了解一下操作系统线程的发展历程,在最初的时候,操作系统没有进程线程一说,执行程序都是串行方式执行,就像一个队列一样,先执行完排在前面的,再去执行后面的程序,这样的话很多程序的响应就很慢,而且有些程序是io型操作居多,很多时间都在等待中浪费了,这时候进程应运而生,现在面试的都知道进程是资源管理的最小单位,线程是cpu调度的最小单位(其...