划重点:谈谈你对进程的理解
谈谈你对进程的理解?
进程是一个程序的抽象:
进程是程序为了完成任务执行得一次过程,是一个动态的,因为每个程序大小不同、资源占用不同,系统为了方便管理,将所有的程序都统一按照进程来进行管理
进程是资源分配的最小单位:
因为所有程序都被抽象成为一个一个的进程,操作系统分配资源时,都是按照进程为单位分配的,并且每个进程在启动初期,都会申请一个0-4G的虚拟空间,其中0-3G为用户空间,3-4G是内核空间,其中0-3G是进程之间独有的空间,互不影响,3-4G属于多进程的共享空间用于进程间通信。
又因为每个进程都有独立的运行地址空间,这就会使进程与进程之间互不干扰,一个进程的消亡,不会影响到其他进程,所以它是一种安全的任务机制。
但是给每个进程分配独立的地址空间这种多任务机制也暴露出了它的缺点,它的开销比较大,因为每个进程都会占用一个独立的地址空间
进程的调度是由内核的调度算法,调度算法实际上是前期把进程划分了不同状态,在用户层有三态,分别是执行态、就绪态和阻塞态,就绪→执行:处于就绪状态的进程,当进程调度程序为之分配了处理机后,该进程便由就绪状态转变成执行状态;执行→就绪:处于执行状态的进程在其执行过程中,因分配给它的一个时间片已用完而不得不让出处理机,于是进程从执行状态转变成就绪状态;执行→阻塞:正在执行的进程因等待某种事件发生而无法继续执行时,便从执行状态变成阻塞状态。在三态下建立了一些基本策略,先到先服务,时间片轮转,和高优先级优先。进程的调度算法有CFS、idul,这些都是内核功能的调度算法,这是内核实现的,
在进程的执行中可能产生僵尸进程和孤儿进程,
因为子进程的资源是要靠父进程回收的。孤儿进程本身是无害的,指的是父进程先于子进程退出,这是子进程会默认init进程为父进程,等子进程运行结束时,init进程负责回收子进程,
然而僵尸进程是有危害的,父进程正在执行,子进程退出,但父进程没有及时回收子进程的资源,导致资源占用浪费。
避免僵尸进程的方式有三种,
第一种是通过信号机制调用SIGCHLD信号,在处理函数中调用wait回收资源;
第二种是fork两次,将子进程变为孤儿进程,从而使其父进程变为init进程,让init进程回收资源;
第三种调用wait和waitpid,
wait是阻塞等待回收,使父进程挂起,等待子进程退出时,回收子进程资源,但是没有起到多进程的作用,同时浪费资源,
waitpid是非阻塞回收资源,但是需要一直查看子进程状态,比较占用CPU资源
我们在用户层主要需要掌握,进程的创建,和进程间通信
Linux提供了四种创建进程的方式,fork、vfork、exec函数族和system,fork是子进程拷贝父进程的数据段,子进程的执行次序不定,
而vfork是子进程与父进程共享数据段,是子进程先执行,父进程后执行,fork的工作原理是给进程复制一个一模一样的空间,
vfork在调用exec之前,都是共享的父进程的空间,他执行的是一种写时复制,内核里面也是写时复制,exec函数族和system都是调用另一个程序
当创建完子进程后,子进程先共享父进程的资源,如果双方有一方去修改内容,修改之前先复制一份到子进程中
进程通信原理
尽管进程空间是各自独立的,相互之间没有任何可以共享的空间,但是至少还有一样东西是所有进程所共享的,那就是OS,因为甭管运行有多少个进程,但是它们共用OS只有一个。既然大家共用的是同一个OS,那么显然,所有的进程可以通过大家都共享第三方OS来实现数据的转发。因此进程间通信的原理就是,OS作为所有进程共享的第三方,会提供相关的机制,以实现进程间数据的转发,达到数据共享的目的
进程通信方式主要分为三大类
- 传统通信方式
- 无名管道
无名管道只允许具有血缘关系的进程间通信,如父子进程间的通信
- 有名管道
具体来说就是,内核会开辟一个“管道”,通信的进程通过共享这个管道,从而实现通信。
管道只允许单向通信,但是可以建立双管道实现双向通信
读管道时,如果没有数据的话,读操作会休眠(阻塞),写数据时,缓冲区写满会休眠(阻塞)
数据被读出,数据就会被管道删除;
- 信号
信号是一种向进程发送通知,告诉其某件事情发生了的一种简单通信机制
向进程发送信号,调用kill
信号处理方式分为三种,忽略,捕捉,默认
sighandler_t signal(int signum, sighandler_t handler);
忽略:SIG_IGN
默认:SIG_DFL
捕获:填写类型为void (*)(int)的捕获函数的地址
- IPC通信方式(第五代操作系统)
- 消息队列
消息队列的本质就是由内核创建的用于存放消息的链表,由于是存放消息的,所以我们就把这个链表称之为消息队列
消息队列的组成:
通常定义一个结构体,结构体一个变量放置消息编号,识别消息用的
,一个放置消息内容,真正的消息内容
Struct msgbuf
{
Long mytype;
Char mtex[msgsz];
}
使用msgget函数穿件新的消息队列、或者获取已存在的某个消息队列,并返回唯一标识消息队列的标识符(msgid),后续收发消息就是使用这个标识符来实现的
通过msgctl函数删除
- 信号量
信号量其实是OS创建的一个共享变量,进程在进行操作之前,会先检查这个变量的值,这变量的值就是一个标记,通过这个标记就可以知道可不可以操作,以实现互斥。
- 共享内存
让同一块物理内存被映射到进程A、B各自的进程地址空间,进程A可以及时看到进程B对共享内存中数据的更新
- 网络通信
套接字
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
