在开始阅读之前,如果你对已介绍的内容还不了解的话,可以先阅读以下文章快速熟悉一下~
5分钟,带你了解汽车操作系统
漫谈QNX(1)–架构
进程包含一个以上的线程和许多资源
举个形象的例子:
Process来控制所有的设备(钻孔机,传送带等),每一种设备就可以想象成一个个thread。
当然还有一些更多的层级关系:
接下来两个多线程的进程的例子(multithreaded processes):
一个process里的threads都有属于自己的内存地址(虚拟地址),其他的资源都是共享的。
每一个thread都有一个最大的体积,也不是每一个都需要分配物理内存。
1 进程Process
fork(), exec*(), spawn(), spawn*(), posix_spawn()
举个例子fork():
fork 这个英文单词在英文里是”分叉”意思, fork() 这个函数作用也很符合这个意思. 它的作用是复制当前进程(包括进程在内存里的堆栈数据)为1个新的镜像. 然后这个新的镜像和旧的进程同时执行下去. 相当于本来1个进程, 遇到fork() 函数后就分叉成两个进程同时执行了. 而且这两个进程是互不影响.
实际应用中, 单纯让程序分叉意义不大, 我们新增一个子程序, 很可能是为了让子进程单独执行一段代码. 实现与主进程不同的功能. 要实现上面所说的功能, 实际上就是让子进程和主进程执行不同的代码啊. 所以fork() 实际上有返回值, 而且在两条进程中的返回值是不同的, 在主进程里 fork()函数会返回主进程的pid, 而在子进程里会返回0! 所以我们可以根据fork() 的返回值来判断进程到底是哪个进程, 就可以利用if 语句来执行不同的代码了!
2 线程Thread
pthread_create()可以用来创建线程。
每个线程其实就是执行一个fun(). 每一个fun()就是一个thread。
pthread_create()会返回tid(thread ID).
pthread_attr_init()可以设置一个线程的default值。
如果你想设置thread优先级和调度算法:
param.sched_priority = 15; %优先级值为15
pthread_attr_setschedparam (&attr, ¶m); %给该thread设定优先级
pthread_attr_setschedpolicy (&attr, SCHED_RR); %设定调度算法为Round-Robin
Process里面,第一个thread就是main thread, 因为它调用了整个process的main()函数. 如果exit()被调用,那么整个process就结束死亡了。
同样的道理,如果在一个thread里, 如果pthread_exit()被调用了,那么thread也就会结束死亡。
如果一个process里面,所有的threads都死亡了,那么这个process就会死亡。
无论process如何死亡的,所有的相应的资源(内存,channels等)都会被释放或清理。
3 同步Synchronization
多threads却引入了新的问题,比如公用内存空间,多个writers可能会互相覆盖对方的值, readers也不知道什么时候数据是稳定有效地。
所以我们需要同步机制来协调管理。
3.1 Mutual exclusion
Mutual exclusion意味着只有一个thread在某一时间里可以执行某段重要的代码段,或者读写一些特别的数据。一个形象的例子:
把厕所空间比喻成内存空间,每次只能进去一个人,里面有人的时候,其他人就不能进去了。这代表一个thread使用某些共享内存时,其他线程必须等它结束,才能使用这一块内存. 问题是如何防止别人也同时进去呢?
一个防止他人进入的简单方法,就是门口加一把锁。先到的人锁上门,后到的人看到上锁,就在门口排队,等锁打开再进去。这就叫“互斥锁”(Mutual exclusion,缩写 Mutex),防止多个线程同时读写某一块内存区域。
其实我的理解就是Mutex就是一个process内的对于所有threads来说的全局01变量,你要锁的时候就把这个全局变量Mutex设置为1,其他的thread读到这个Mutex的时候就知道你在使用,就停下来等,知道你用完了把Mutex设置回0,然后别的进程才可以进去用。
当然这样又会产生新的问题,死锁问题(Dead lock). 对此,我们可以设计一些特殊的执行顺序来避免死锁,这里就不打算展开了。
当然一旦锁定了Mutex,该thread的优先级就会上升。因为系统当然希望这个thread赶紧运行完毕,毕竟不能占着茅坑不拉屎。
3.2 条件锁Condvars
光有互斥锁还是不够,最好有一把聪明的互斥锁。比如说,只有满足了某种条件(收到某种信号)的情况下,才能解锁。这样就会更高效的执行程序功能。
其实总体看起来,线程的执行很像最近流行的宫廷剧里,一个皇上(CPU)拥有很多嫔妃(Threads),但是宗旨是雨露均沾。所以如何雨露均沾就是一件需要调度和协调的事情,最后还尽量要让嫔妃们都满意,苦了皇上了,哈哈。
版权声明:本文为知乎博主「强大的宇宙」原创文章
原文始发于微信公众号(Vehicle攻城狮):漫谈QNX(2)–进程,线程,同步