zoukankan      html  css  js  c++  java
  • UI线程与worker线程

    也谈谈我对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线程把它拷贝过来后置于栈顶,那栈可用空间不够大怎么办。此外还有种种我这水平未能触及的原因,发现真要这么做的话,这代价实在太高了,还不能保证如预期那样进行。

  • 相关阅读:
    PHP数组(数组正则表达式、数组、预定义数组)
    面向对象。OOP三大特征:封装,继承,多态。 这个讲的是【封存】
    uvalive 3938 "Ray, Pass me the dishes!" 线段树 区间合并
    LA4329 Ping pong 树状数组
    HDU 1257 最少拦截系统
    HDU 1260 Tickets
    codeforce 621D
    codeforce 621C Wet Shark and Flowers
    codeforce 621B Wet Shark and Bishops
    codeforce 621A Wet Shark and Odd and Even
  • 原文地址:https://www.cnblogs.com/keanuyaoo/p/3285725.html
Copyright © 2011-2022 走看看