1、进程
进程是任何多道程序设计的操作系统中的基本概念。通常把进程定义为程序执行的一个实例,因此,如果有16个用户同时运行vi,那么就有16个独立的进程(尽管他们共享一个可执行代码);
有个比喻,进程类似于人类:它们被产生,有或多或少有效的生命,可以产生一个或多个子进程,最终都要死亡。一个微小的差异是进程之间没有性别差异——每个进程都只有一个复亲。
从内核看,进程的目的就是担当分配系统资源(cpu时间,内存等)的实体。
1.1进程的创建
通常有以下4种情况会导致新进程产生:
- 1、在一个交互环境中,当一个新用户在终端键入登录命令后,如实合法用户系统将为该用户建立一个进程
- 2、在一批处理环境中,为了响应一个任务的要求而产生进程。
- 3、当运行中获取用户程序提出的某种请求后,os可以代用户程序产生进程以实现某种工能,是用户不必等待。
- 4、基于应用进程的需要,由已存在的进程产生另一个进程,以便新程序的并发运行方式完成特定任务
进程的创建用fork或者vfork函数。
当一个进程创建时,它几乎与父进程相同。它接受父进程地址空间的一个(逻辑)拷贝,并从进程创建系统调用的下一条指令开始执行与父进程相同的代码。尽管父子进程可以共享好友程序代码的页,但他们各自有独立的数据拷贝(堆和栈),因此子进程堆一个内存单元的修改对父进程是不可见的。
int mian(){
pid_t pid;
int x =1;
pid = Fork();
if (pid == 0){/*child*/
print("child : x=%d\n", ++x);
exit(0);
}
/*parent*/
printf("parent: x=%d\n", --x);
exit(0);
}
linux> ./fork
parent: x=0
child : x=2
1.2fork函数和vfork函数的区别
- 1、fork函数:子进程拷贝父进程的数据段和代码段
- 2、fork函数:父子进程的执行次序不确定
vfork函数:保证子进程先运行,在调用exec或者exit 前与父进程数据是共享的,在它调度exec或exit之后父进程才可能
被调度运行
2、进程状态
进程描述符中的state字段描述了进程当前所处状态。它由一组标志组成,其中每个标志描述一种可能的进程状态,在当前linux版本中,这些状态是互斥的
(1)可运行状态(TASK_RUNNING)
进程要么在cpu运行,要么准备执行
(2)可中断的等待状态(TASK_INTERRUPTIBLE)
进程被挂起(睡眠),直到某个条件变为真
(3)不可中断的等待状态(TASK_UNINTERRUPTIBLE)
与可中断的等待状态类似,但有一个例外,把信号传递到睡眠进程不能改变他的状态
(4)暂停状态(TASK_STOPPED)
进程的执行被暂停。当进程接收到SIGSTOP、SIGTSTP、SIGTTIN或SIGTTOU信号后,进入暂停状态
(5)跟踪状态(TASK_TRACED)
进程的执行已由debugger程序暂停。当一个进程被另一个进程监控时,任何信号都可以把这个进程置于TASK_TRACED状态
(6)僵死状态(EXIT_ZOMBIE)
进程的执行别终止,但是,父进程还有发布wait4()或waitpid()系统调用来返回有关死亡进程的消息。
(7)僵死撤销状态(EXIT_DEAD)
由于父进程刚发出wait4()或waitpid()系统调用,因而进程由系统删除。为了防止其他执行线程在同一个进程上也执行wait()类系统调用,而把进程的状态有僵死(EXIT_ZOMBIE)状态改为僵死撤销状态
3、进程切换
3.1中断进程执行的事件
中断:来自当前指令的执行的外部,一般的中断,控制权被转移给中断处理程序,如I/O操作完成
陷阱:同当前指令有关,处理错误或意外情况;分为两种程度“致命”切换线程,“不致命”os会根据错误的性质和自身的设计进行处理
监管调用:明确的请求,来自执行程序的监管调用会激活操作系统(又如发送I/O等待请求),这个调用会导致处理器转向执行一段操作系统代码。进程转入阻塞状态。
3.2进程切换步骤:
- 1、保存处理器的内容;
- 2、对当前运行进程的PCB进行更新,包括改变进程状态和其他相关信息。
- 3、将这个进程的PCB移入适当的队列(就绪,阻塞,挂起等)
- 4、挑选其他进程执行
- 5、对挑选进程的pcb进行更新,包括其状态改为运行
- 6、对存储器管理数据结构进行更新
- 7、将被选中进程上次移出时处理器状态进行恢复
4、多进程
同一时间里,一个计算机系统里允许两个或两个以上的进程同时运行,即为多进程。多进程带来的好处是你可以边听mp3边上网,与此同时甚至可以将下载的文档打印出来,而这些任务之间丝毫不会相互干扰。
5、进程间的通信
进程通信指的是进程间的信息交换,主要有以下几种方法
- 1、管道pipe:管道是一个半双工的通信方式,它只允许单向流动,而且只能在具有亲缘关系的进程间使用。亲缘关系是指父子关系。
- 2、命名管道FIFO:有名管道也是半双工的通信方式,但它允许非亲缘关系进程间进行通信。
- 3、信号量:信号量是一个计数器,用来控制多个进程对资源的访问,它通常作为一种锁机制。
- 4、消息:允许进程在预定义的消息队列中读和写消息来交换信息
- 5、共享存储区:就是映射一段能被其他进程访问的内存,允许进程通过共享内存块来交换信息。在必须共享大量数据的应用中,这可能是最高效的进程通信方式
- 6、socke套接字:允许不同计算机上的进程通过网络交换数据。套接字还可以用作相同主机上的进程之间的通信工具
- 7、信号:是一种比较复杂的通信方式,用于通知接受进程某个事件已经发生。
6、三种特殊进程
6.1.孤儿进程:父进程终止,交由init进程管理
6.2.僵尸进程:子进程终止状态,但父进程还未获取其状态并将其回收
6.3.守护进程:在后台运行,不与任何终端关联的进程,通常情况下,守护进程在系统启动时就在运行。他们以root用户或者其他特殊用户运行,并能处理一些系统级的任务
6.3.1守护进程创建步骤
调用fork函数,创建新进程,它会是将来的守护进程。
在父进程中调用exit,保证子进程不是进程组长
调用 setsid函数 创建新的会话区
将当前目录改成根目录
将标准输入输出,标准错误重定向到/dev/null
7、进程和线程的区别
7.1进程是资源的分配和调度的一个单元,线程是cpu调度的基本单元
7.2同一进程中可以包含多个线程,并且线程共享整个进程的资源,一个进程至少包括一个线程
7.3进程用fork或vfork创建,进程的创建调用pthread_create,进程结束后,它所拥有的所有线程都被销毁,而线程的结束不会影响整个进程中的其他线程。
7.4线程是轻量级进程,创建和销毁所需要的时间比进程小很多,所有操作系统中的执行功能都是创建线程去完成的
7.5线程中执行时一般都要进行同步和互斥,因为他们共享同一进程的所有资源
7.6线程有自己的私有属性TCB、线程id、寄存器和上下文,进程也有自己的私有属性控制块PCB