例1:从fork()看线程
fork()创建新进程的系统调用。定义一个变量Pid,存储进程号,然后做fork操作,子进程就产生了,继承了父进程的所有资源,代码,堆栈,打开文件等等。如果是父进程,fork返回了子进程的pid,如果是子进程,fork返回0,可以用这个返回值区分父子进程。
int main(){
int pid = 0;
printf("the parent is going to fork\n")
if(pid = fork() != 0){
printf("I am the father of %d\n", pid);
} else{
printf("I am the child\n");
}
}
这个例子,可以看到程序是静态的,但是进程执行代码过程中的轨迹是动态的,父子进程就有不同的结果,有跳转有判断。这样的动态跳转就给操作系统带来了麻烦。跳转判断的过程留下了线索,怎么样去准确的反映这个线索?这就是提出线程概念的意图之一。
PS:老师提的这个例子其实我没有看懂。。进程PCB里面不是有program counter?难道进程不能跟踪线索?这个问题先留着。
例2:单线程VS多线程
假设单线程模式,一个选课系统,1000个学生区分这些人那就要有1000个进程,这些进程的代码几乎是一样的,进程创建很消耗时间,那个数据结构也很大,那就要1000个PCB,有人问难道不能共享代码和数据?好,有可能共享一部分代码和数据,或许用不来那么多的空间。那调度时候Context Switch频繁切换,会有很大很大的开销,这有多难多恶心。。可想而知。
这也是提出线程概念的另一个意图。
定义来了!
在一个任务下面包含了若干个线程,这若干个线程共享了一个大任务的一些资源(代码、数据、文件等),每个线程有独立的资源(寄存器、栈、程序计数器等)。(是有层次的,一定要强调一个任务下面)
线程可以解决例子中的两个问题:
- 每个线程都有自己的Program counter,所以可以跟踪不同线程的轨迹。
- 另外线程还能共享那些公共资源,没有太多空间消耗。线程切换也不存在Context Switch的问题。
除了上面的两点,还有下面的优点:
- 对多处理器或者多核(算数逻辑单元独立,共享了cache)系统,可以让每一个核去对应执行一个线程,而单线程进程只能运行在一个CPU(核)上,多线程在多CPU或多核系统中加强了并发功能。
- 响应度高,多线程即使部分阻塞或者执行较冗长的操作,该程序仍然能继续执行。
网友评论