RunLoop笔记(转载自Noah)

原文链接19楼

心中先有一个抽象的概念,抽象的模型。考虑一下以下这些问题
1,线程是怎么工作的,只要执行完所有任务它就挂了。
2,事件(event)是怎么接收的?例如I/O事件,用户触摸屏幕后事件是怎样传递的?线程是怎么捕获这些事件的?
3,GUI程序或CLI程序有什么区别?

这个程序只有一条线程,当函数return后线程也就挂了,由于这是唯一的线程,所以进程也一并挂了。

int main(int argc, char *argv[]) {
  printf("hello world");
  return 0;
}

另外知道什么是(用户态)User mode和(内核态)Kernel mode吗?这两者是属于操作系统方面的知识。这里举个比较实际的例子会比较容易理解。例如要将字符串写进某个文件。步骤分别是。

stringToWrite = "hello world"
path = "/my_file.txt"
writeTo(path, stringToWrite)

1,构造一个字符串变量 ————用户态
2,构造目标地址 ————用户态
3,用当前语言的标准库在对应的目录上构造文件,并将字符串写进去 ————用户态————>内核态

在程序执行到某一段时,程序调用了一个system call函数通知操作系统内核去做某些操作,该操作只有操作系统内核才权限去做,本地程序做不到。I/O操作就是典型的system call。用户态通过system call进入内核态,这时writeTo这个函数会堵塞,因为它需要等待操作内核将结果返回,I/O操作是非常耗时的。这是一种典型的同步程序,writeTo需要等候操作系统内核返回结果才能return,线程直接堵塞在这里。

聪明的你大概会想,这个程序跑到这里只能等操作系统完成工作,结果什么做不了,造成CPU资源浪费,因为这个耗时操作不是大量的运算,而只是I/O访问而已,所以CPU是闲着的。本着最大利用CPU的资源的原则,应该要怎么做?分一条线程出来将writeTo放进去不就得了,主线程就不会堵了。但你有没有发现一点,尽管我们不希望等,但也需要知道writeTo的结果啊,这怎么办?线程间通信咯。。。但怎么做?思考一下。下面的写法是无法在两个线程之间进行通信的。

main {
  thread = Thread(threadEntry)
  thread.run()
  return
}


threadEntry {
  stringToWrite = "hello world"
  path = "/my_file.txt"
  writeTo(path, stringToWrite)
  return
}

有一个比较简单的方法是将结果存到一个全局变量里,这样两个线程都能访问。在两个线程入口函数外声明一个变量result,并将writeTo的结果填入。

threadEntry {
  stringToWrite = "hello world"
  path = "/my_file.txt"
  result = writeTo(path, stringToWrite)
  return
}

好了,最后是你需要思考的问题,相通了再来看Runloop会发现。。。就是这么一回事。
问题是在主线程的入口main函数里,我们要怎么拿到result的值?

main {
  thread = Thread(threadEntry)
  thread.run()
  if result {
    // 如果写在这里,result根本都还没被赋值
  }
  return
}

————————————————————————————————————————————————————————————————————————————————————
扩展阅读,题外话。。。可以跳过
说到Runloop,其实在node.js里有一个很相似的机制叫做EventLoop的,事件循环。node.js是一个执行平台,环境。。。。执行的是JS代码。它是单线程的。。但几乎所有I/O操作都是异步的。
与apache不同的是,在接收用户的请求后,node不会给你创建新的线程来响应这个请求。apache则会,每一个请求就对应一条线程,所以写PHP的思维很简单,因为所有操作都是同步的,代码一句一句往下写就会按顺序执行。如果执行到某个段落后需要从数据库上查数据,那么该线程直接堵塞掉,直到数据库返回数据。就像上面的例子,没有开出子线程的。这种做法的缺点也是明显的,如果大量的用户请求,那么则需要开出大量的线程,假设这些请求都是从数据库里查找数据,那么CPU资源就会严重的浪费,因为I/O操作不需要太多CPU资源。大量的线程也会占用大量的内存。。。node的话是一个奇葩,它只有单线程,为了实现能处理多个请求,它必须要有一个none-blocking机制,如果每次请求都得堵一下,用户不给你炸了。
node的模型是这样的,通过一个入口函数来接收请求,然后执行一会儿直到需要进行I/O操作。。。node会将回调函数和一个任务标识扔到一个队列里进行等候并立即返回。这时node就可以继续处理第二个请求,直到需要I/O,继续放到队列里去。。。当第一个I/O操作完成后,node会将这对标识和回调函数的组合移动到。。。事件队列里等候调用。

node里有一个循环机制,每次循环node都会历遍两个队列里的元素,判断一下那一个元素对应的I/O请求完成了,然后将它放到事件队列。历遍事件队列来调用元素内对应的回调函数。。。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 心中先有一个抽象的概念,抽象的模型。考虑一下以下这些问题1,线程是怎么工作的,只要执行完所有任务它就挂了。2,事件...
    HT_Jonson阅读 663评论 0 51
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 135,180评论 19 139
  • 你是花田间的七里香 开出淡淡的芬芳 有个忧伤的姑娘 在你盛放的路旁 看着你,哀怨又彷徨 你是北极上的一束光 越过星...
    江南少城主阅读 271评论 6 5
  • 今年的年度大戏《那年花开月正圆》已经完美收官,引发了今年下半年的观剧热潮。观剧时,人们被陕西首富周莹的经商头脑、大...
    孤独的青狼阅读 503评论 0 0
  • 一时兴起,我百度了“礼尚往来”这个成语,令我很是幸运的得到了很多有趣的信息和浓厚的知识,接着就细细的探讨了很多有关...
    阿俊xi阅读 383评论 0 0