多线程设计的合理性
简单和安全胜过复杂和速度
多线程设计应该是以最低的表面积来设计,这里的“表面积”是指必须被线程共享的数据结构,当然共享的数据结构越少,
我们需要做的逻辑处理就越简单,反之,线程安全控制复杂度就会比较高!所以以“最低密度”进行程序设计才是我们的目标!
2.关于GUI线程恶化work线程
2.1.所谓的worker线程,是指完全不牵扯到图形用户界面(GUI),纯粹做运算的线程。
2.2.微软的多线程模型【转载】:
Win32说明文件一再强调线程分为GUI线程和worker线程两种。GUI线程负责建造窗口以及处理主消息循环。Worker负责执行纯粹的运算工作,如重新计算或重新编页等,这些运算工作会导致主线程的消息队列失去反应。一般而言,GUI线程绝不会去做那些不能够马上完成的工作。
GUI线程的定义是:拥有消息队列的线程。任何一个特定窗口的消息总是被产生这一窗口的线程抓到并处理。所有对此窗口的改变也都应该由该线程完成。
如果worker线程也产生了一个窗口,那么就会有一个消息队列随之被产生出来并且附着到此线程身上,于是worker线程摇身一变成了GUI线程。这里的意思是:worker线程不能够产生窗口、对话框、消息框,或任何其他与UI有关的东西。
如果一个worker线程需要输入或输出错误信息,它应该授权给UI线程来做,并且将结果通知给worker线程。
消息队列是一个链表,只有在必要的时候,才有元素产生出来。具体的关于消息队列的数据结构,可以参考相关的windows文档。
2.3.在Win32中,每一个线程有它自己专属的消息队列。这并不意味着每一个窗口有它自己的消息队列,因为一个线程可以产生许多窗口。如果一个线程停止回应,或是它忙于一段耗时的计算工作,那么由它产生的窗口统统都会停止回应,但系统中的其他窗口还会继续正常工作。
以下是一个非常基本的规则,用来管理Win32中的线程、消息、窗口的互动:
所有传送给某一窗口之消息,将由产生该窗口之线程负责处理。
比方说,使用SetWindowText来更新一个Edit框的内容,其实就是发出了一个WM_SETTEXT消息给edit窗口函数。推而广之,每一个控件都是一个窗口,都拥有自己的窗口函数。
对窗口所作的一切事情基本上都会被该窗口的窗口函数处理,并因此被产生该窗口的线程处理。
当需要发送一个消息时,Windows会自动计算出哪一个线程应该接收到消息(以便确定该消息实体应该挂在在哪一个线程的消息队列中)。同时,windows还会确定线程应该如何被告知有这么一个消息进来。一共有四种可能:
(1)如果属于同一线程,使用SendMessage传递消息,则直接调用窗口函数。
(2)如果属于同一线程,使用PostMessage传递消息,则把消息放在消息队列中然后立即返回。
(3)如果不属于同一线程,使用SendMessage传递消息,则切换到新线程中并调用窗口函数。在该窗口函数结束之前,SendMessage不会返回。
(4)PostMessage立刻返回,消息则被放到另一线程的消息队列中。
当我send一个消息给另一线程掌握的窗口时,系统必须做一次context switch,切换到另一线程去,调用该窗口函数,然后再做一次context switch切换回来,相对一般的函数调用而言,期间的额外负担较大。如果在MDI中,为每个子窗口分配一个线程,那么该子窗口的所有资源——包括画刷,DC,调色板等等都属于线程的资源。此时为线程做context switch时会代价很大。
3.设计窗口程序(多线程worker数据处理)
3.1 数据必须进行拷贝,各个线程拥有一份,互不影响;
3.2 涉及到界面的显示,交由GUI程序来处理;
3.3 各个线程间不要共享GDI(图形设备接口);
4.虽然这是windows多线程的处理,但是我们还是可以借鉴其设计思想.主线程负责逻辑,子线程负责算法,最难的恐怕就是线程间数据的共享的处理了。
阅读(605) | 评论(0) | 转发(0) |