进程包含一个以上的线程和许多资源
举个形象的例子:
组装线
Process来控制所有的设备(钻孔机,传送带等),每一种设备就可以想象成一个个thread。
当然还有一些更多的层级关系:
接下来两个多线程的进程的例子(multithreaded processes):
1. 一个实时性要求很高的进程和硬件进行通信,其他的线程可以慢条斯理的和其他process进行通信
2. Pool of worker threads. 很多线程准备着,当其他线程都忙的时候,新的请求依旧可以有线程来满足
一个process里的threads都有属于自己的内存地址(虚拟地址),其他的资源都是共享的。
一个process的虚拟地址
每一个thread都有一个最大的体积,也不是每一个都需要分配物理内存。
1 进程Process
fork(), exec*(), spawn(), spawn*(), posix_spawn()
举个例子fork():
fork() will create a copy of your process
fork 这个英文单词在英文里是"分叉"意思, fork() 这个函数作用也很符合这个意思. 它的作用是复制当前进程(包括进程在内存里的堆栈数据)为1个新的镜像. 然后这个新的镜像和旧的进程同时执行下去. 相当于本来1个进程, 遇到fork() 函数后就分叉成两个进程同时执行了. 而且这两个进程是互不影响.
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
其实我的理解就是Mutex就是一个process内的对于所有threads来说的全局01变量,你要锁的时候就把这个全局变量Mutex设置为1,其他的thread读到这个Mutex的时候就知道你在使用,就停下来等,知道你用完了把Mutex设置回0,然后别的进程才可以进去用。
当然这样又会产生新的问题,死锁问题(Dead lock). 对此,我们可以设计一些特殊的执行顺序来避免死锁,这里就不打算展开了。
当然一旦锁定了Mutex,该thread的优先级就会上升。因为系统当然希望这个thread赶紧运行完毕,毕竟不能占着茅坑不拉屎。
拥有Mutex的thread的优先级就会上升
3.2 条件锁Condvars
光有互斥锁还是不够,最好有一把聪明的互斥锁。比如说,只有满足了某种条件(收到某种信号)的情况下,才能解锁。这样就会更高效的执行程序功能。
其实总体看起来,线程的执行很像最近流行的宫廷剧里,一个皇上(CPU)拥有很多嫔妃(Threads),但是宗旨是雨露均沾。所以如何雨露均沾就是一件需要调度和协调的事情,最后还尽量要让嫔妃们都满意,苦了皇上了,哈哈。