也谈谈我对UI线程和worker线程的理解

UI线程又叫界面线程,能够响应操作系统的特定消息,包括界面消息、鼠标键盘消息、自定义消息等,是在普通的worker线程基础上加上消息循环来实现的,在这个消息循环上不断地获取操作系统或其他线程派发过来的消息(就是个线程里面执行for循环的主),再根据这个消息找到对应的消息处理对象/函数,如果暂时没有消息需要处理就让线程等待,让出CPU时间片,以此表现出该线程一直“在线”的状态,直到某一特定退出消息结束线程。

worker线程又叫工作者线程,为了不影响UI线程的长时间任务处理导致的界面操作阻塞,提升用户体验,开以考虑开辟一个worker线程来完成复杂的任务,任务处理完后可以让它立即退出也可以让它继续等待新的任务,看具体需要。一个处理完任务后不退出而处于等待状态的worker线程其实跟UI线程已经没多大区别了,在worker线程也可以自己实现一个任务队列,然后不断地获取任务来达到UI线程的效果。

不管在什么操作系统,UI线程与worker线程协同工作不可避免地都会面对线程同步执行的问题,这里同步执行不是“对象状态同步”的概念,而是将线程执行“串行化”,比如线程A要执行后续的代码段之前先要等待线程B完成某一特定任务,当然,也可以通过“对象状态同步”的方式来达到这个效果,只是会比较麻烦一点。

以windows系统为例,当worker线程处理完结果后,需要把结果返回给UI线程,好让界面能够更新显示最新的状态,有这么几种方式:

    1.直接在worker线程执行处调用API::SendMessage,把消息和附带参数发往UI线程的消息队列,让UI线程从挂起状态恢复成执行态后从消息泵获取处理,如果当前消息泵没有其他消息,则立即处理此消息,否则需等待其他消息处理完后轮到它才执行,而此时worker线程处于等待消息处理的状态,UI线程处理完消息后,它才继续往下执行;

    2.直接在worker线程执行处调用API::PostMessage,与SendMessage一样,只不过,这是worker线程不等待处理结果,继续往下走,又叫异步方式。如果PostMessage有附带参数,这时就得谨慎处理了,就像普通的线程异步处理一样,对象必须加锁解锁,除非这个附带参数是临时从堆上分配的对象,由UI线程处理完消息前负责释放,但是这又涉及到模块之间的内存申请、释放问题,搞不好,程序直接core dump。

    3.worker线程直接把结果存放于UI线程能访问的某一处,等到UI线程执行到需要用到该结果时才访问,也要对这个对象进行加锁解锁,搞不好容易死锁。

以上3中方法,不管是哪种,处理起来都很麻烦,尽管第一种方式相对比较简单,可是写起代码来还是觉得繁琐,要先定义一个双方认识的消息(还得考虑该消息会不会冲突,是否考虑使用RegisterWindowMessage),定义好消息处理函数,然后添加消息映射宏,而且代码看起来不如顺序执行那么流畅,维护代码时要在这些地方跳来跳去,且还不论有多种同步消息需要同步,时间久了,只会越来越难维护。

接触这种线程“伪同步”一段时间后,自然而然对这种方式反感,开始思考一个问题:为什么操作系统不提供一个线程切换的API供调用,这样多省事啊。等待认真了解线程工作原理后,才发现这想法太天真了。

通常一个线程得以被操作系统调度运行,是因为符合当前优先级配置,且该线程尚有代码需要执行(这样说貌似也不太合理,想不出来),最直观的就是函数调用(不管全局函数也好、构造函数也好。。。),既然是函数调用那肯定有参数、变量入栈出栈,每个线程被挂起后,为了恢复执行后能够之前的状态下继续执行,就必然是一个线程对应一个线程栈,以此线程间互不干扰,各自在自己的一亩三分地上干活。这时再考虑线程“串行化”的问题,如果系统要提供线程切换的API,那么worker线程需要与UI线程同步时就必须让UI线程切换到worker线程拥有的线程栈上来,否则如何访问worker线程中的那些变量、参数,UI线程切换过来后,之前保留的现场又该怎么处理,如果栈是可拷贝的,那UI线程把它拷贝过来后置于栈顶,那栈可用空间不够大怎么办。此外还有种种我这水平未能触及的原因,发现真要这么做的话,这代价实在太高了,还不能保证如预期那样进行。

UI线程与worker线程的更多相关文章

  1. 模板应用--UI线程与worker线程同步 模仿c# invoke

    由之前的一篇博文 <UI线程与worker线程><UI线程与worker线程>引出,UI线程与worker线程“串行化”在win32上实现是多么没有节操的事情,代码编写麻烦不说 ...

  2. 在netty3.x中存在两种线程:boss线程和worker线程。

    在netty 3.x 中存在两种线程:boss线程和worker线程.

  3. Android 实战之UI线程和Worker线程交互

    哈哈,博文取了个比较霸气的名字,大家不都喜欢这样忽悠人吗 呵呵! 好了,现在就是很简单的点击查询,然后这个查询有点花时间,不想见面出现假死现象,所以在另外的线程进行查询. 好了,代码在此: packa ...

  4. HTML5_06之拖放API、Worker线程、Storage存储

    1.拖放API中源对象与目标对象事件间的数据传递: ①创建全局变量--污染全局对象:  var 全局变量=null;  src.ondragstart=function(){   全局变量=数据值;  ...

  5. UI线程和工作者线程

    本文转载于:http://blog.csdn.net/libaineu2004/article/details/40398405 1.线程分为UI线程和工作者线程,UI线程有窗口,窗口自建了消息队列, ...

  6. 为什么说android UI操作不是线程安全的

    转载于:http://blog.csdn.net/lvxiangan/article/details/17218409#t2 UI线程及Android的单线程模型原则 使用Worker线程 Commu ...

  7. 【转】 Pro Android学习笔记(九十):了解Handler(4):Worker线程

    目录(?)[-] worker线程小例子 小例子代码worker线程通过handler实现与主线程的通信 小例子代码继承Handler代码 小例子代码子线程的Runnable 文章转载只能用于非商业性 ...

  8. C# 多线程详解 Part.02(UI 线程和子线程的互动、ProgressBar 的异步调用)

           我们先来看一段运行时会抛出 InvalidOperationException 异常的代码段: private void btnThreadA_Click(object sender, ...

  9. Android的UI设计与后台线程交互

    本文将讨论Android应用程序的线程模型以及如何使用线程来处理耗时较长的操作,而不是在主线程中执行,保证用户界面(UI)的流畅运行.本文还将阐述一些用户界面(UI)中与线程交互的API.UI用户界面 ...

随机推荐

  1. SQL Server 造成cpu 使用率高的 6 原因

    第一种: 编译和重编译执行计划. 第二种: 排序与聚合. 第三种: 表格连接操作. 第四种: max degree of parallelism. 第五种: max worker threads. 第 ...

  2. 定制化Azure站点Java运行环境(1)

    Azure website提供了为现代化的web应用程序快速部署的PAAS平台,可以让用户几分钟之内快速的将自己的应用部署到云端,并且提供了自动扩展(auto-scaling),SSL,多种语言(Ja ...

  3. android layout的布局

    1.android:layout_width.android:layout_heigth 表示控件的大小,长宽 2.andoid:layout_gravity .android:gravity表示控件 ...

  4. Inno Setup 打包工具总结(转)

    最近打包用到了Inno setup,在这个过程中容易犯一些低级错误,特别写出来已提醒自己 1.打包文件夹 打包文件按照向导来一般没什么问题,但文件夹就不一样了.向导生成的打包文件夹的代码如下: Sou ...

  5. 网易云课堂_C++开发入门到精通_章节2:引用和函数的高级用法

    课时6函数重载 函数重载 在C语言头文件中的extern "C" //常见的C语言头文件格式 #ifndef _FUNC_ #define _FUNC_ #ifdef __cplu ...

  6. Android SDK目录结构和工具介绍

    Android SDK目录结构和工具介绍是本文要介绍的内容,主要是来了解并学习Android SDK的内容,具体关于Android SDK内容的详解来看本文. AD: Android SDK目录结构和 ...

  7. Android学习之Notification

    Notification可以在手机的状态栏发出一则通知,它需要用NotificationManager来管理,实现Notification其实很简单. 1.通过getsystemservice方法获得 ...

  8. (三)Android中Intent概念及应用

    一.显示Intent startActivity(new Intent(MainActivity.this,BAty.class)); 显示Intent直接指定要启动的Intent类 注意自己通过创建 ...

  9. Android中 Http请求

    HttpClient public class MainActivity extends Activity { private Button button; @Override protected v ...

  10. 关于DLL中Resources文件修改

    1.先用IL DASM工具将所需要修改的DLL进行文件转换成IL文件,其中*.il文件就是代码,*.resources,这个文件就是资源. 2.找到需要修改的resources文件 //新文件 IRe ...