线程分:ui线程和工作线程
概念:
在Windows中,UI控件也被视为一个“Window”,它也拥有自己的“窗体过程”,因此,它也可以同窗体一样,具备处理消息的能力。
由此我们可以知道UI线程所完成的大致工作就是:
UI线程启动一个消息循环,每次从本线程所对应的消息队列中取出一条消息,然后根据消息所包容的信息,将其转发给特定的窗体对象,此窗体对象所对应的“窗体过程”函数被调用以处理这些消息。
用户操作消息是怎样“跑”到UI线程的消息队列中的?
操作系统会监控计算机上的键盘和鼠标等输入设备,为每一个输入事件(由用户操作所引发,比如用户按了某个键)生成一个消息。根据事件发生时的情况(比如当前激活的窗体负责接收用户按键,而依据用户点击鼠标的坐标可以知道用户在哪个窗体区域内点击了鼠标),操作系统会确定出此消息应该发给哪个窗体对象。
这些生成的消息会统一地先临时放置在一个“系统消息队列(system message queue)”中,然后,操作系统有一个专门的线程负责从这一队列中取出消息,根据消息的目标对象(就是窗体的句柄),将其移动到创建它的UI线程所对应的消息队列中。操作系统在创建进程和线程时,都同时记录了大量的控制信息(比如通过进程控制块和句柄表可以查找到进程所创建的所有线程和引用的核心对象),因此,根据窗体句柄来确定此消息应属于哪个UI线程对于操作系统来说是很简单的一件事。
注意,每个UI线程都有一个消息队列,而不是每个窗体一个消息队列!
那么,操作系统是不是会为每一个线程都创建一个消息队列呢?
答案是:只有当一个线程调用Win32 API中的GDI(Graphics Device Interface)和User函数时,操作系统才会将其看成是一个UI线程,并为它创建一个消息队列。
需要注意的是,消息循环是由UI线程的线程函数启动的,操作系统不管这件事,它只管为UI线程创建消息队列。因此,如果某个UI线程的线程函数中没有定义消息循环,那么,它所拥有的窗体是无法正确绘制的。
mfc中创建ui线程只能通过CWinthread派生下来,动态创建。
终止线程:AfxEndThread PostQuitMessage 获取线程返回值: GetExitCodeThred
一个线程结束后就会处于信号发送状态:WaitforSingleObject(pThread->m_hThread, INFINITE);直到线程返回
同步:
临界区: 通过CCriticalSection 类的Lock() Unlock()同步,就中间添加执行代码,
目的是为了避免俩个或多个线程同时访问一个资源。 执行时最好用InterlockedIncrement
来确保线程安全。(可以设置等待时间)
互斥量:和临界区基本相同,区别在于,临界区用于同一个进程中的线程。互斥量用于,不同进程中
的线程对同一个资源的访问。 CMutex
事件:不说了,经常用。
信号量:不说了,经常用。