Linux 进程

Linux 进程

一.进程
二.进程间关系
三.进程间通信

1.进程

  1. 进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。
    2.linux 进程特性 强亲缘性 父子进程
  2. 进程状态
    主要的进程状态:运行、就绪、挂起、终止,阻塞,僵尸。
    一,创建原语:fork函数族
    在liunx中使用函数fork创建新的进程。
    是fork()里面的GREATE(创建壳) GLONE(初始化拷贝)函数完成的
    函数特点:调用一次,返回两次。
    在父进程中,返回创建的子进程的pid;在子进程中返回0;出错,返回-1。
    1,fork() (采用读时共享写时复制的细想)
    2,vfork() (只是拷贝父进程内核空间 用户空间需要自己进行申请)
    二,执行(加载)原语:exec函数族
    exec函数以执行另一个程序。当进程调用一种exec函数时,该进程的用户空间代码和数据完全被新程序替换,从新程序的启动例程开始执行。调用exec并不创建新进程,所以调用exec前后该进程的id并未改变。
    1,execl (实现进程功能重载) 一般配合fork()使用
    2,execv
    3,execle
    4,execve
    5,execlp
    6,execvp
    三,退出/等待退出原语:exit函数族,wait函数族
    1,exit
    2,_eixt
    3,wait(回收僵尸进程 阻塞函数)
    4,waitpid(回收僵尸进程 可以设置为非阻塞)
    5,waitid
    进程在操作系统中都有一个户口,用于表示这个进程。这个户口操作系统被称为PCB(进程控制块),在linux中具体实现是 task_struct数据结构,它记录了一下几个类型的信息:
    1.状态信息,例如这个进程处于可执行状态,休眠,挂起等。
    2.性质,由于unix有很多变种,进程有自己独特的性质。
    3.资源,资源的链接比如内存,还有资源的限制和权限等。
    4.组织,例如按照家族关系建立起来的树(父进程,子进程等)。
    在这里插入图片描述
    在这里插入图片描述
    ps命令
    -a,查看所有
    -u,以用户(user)的格式显示
    -x, 显示后台进程运行参数
    -ef,以全格式显示进程所有信息,包括父进程Pid,创建人,创建时间,进程号。等等
    组合 ps aux 查看进程信息 ps ajx 查看系统下进程间关系
    R+ 运行态 S 睡眠态 Z+僵尸态 T挂起态 +表示前台运行

2.进程间关系
进程间关系分为进程组、作业、会话。
1.进程组
概念:进程组是一个或多个进程的集合
特点:
每个进程除了有自己的进程ID之外,还属于一个进程组
进程组与同一个作业相关联,可以接收来自同一终端的各种信号。
每个进程组都有一个唯一的进程组ID,每个进程都可以有一个组长ID
组长进程ID等于进程组ID,组长进程可以创建一个进程组,创建一个进程组中的进程。
只要该进程组中还有一个进程,那么这个进程组就还存在,哪怕进程组长终止。
2.作业
特点:
Shell分前后台,它控制的不是进程而是作业或者进程组
一个前台作业可以由多个进程组成,一个后台作业也可以由多个进程组成
Shell可以运行一个前台作业和多个后台作业,这叫做进程控制
作业和进程组的区别:如果作业中的某个进程创建了子进程,那么子进程不属于作业
一旦作业运行结束,Shell就自己提到前台来,但是子进程还在,子进程又不属于作业。如果原来的前台进程还存在,这个子进程还没有终止,它自动变为后台进程组
前台新起作业,Shell是无法运行的,因为它被提到了后台,只有前台作业终止了,Shell才会被提到前台,可以接受用户输入。
查看后台作业
jobs
将前台作业提至后台
bg 1(作业号) 先要contrl C终止后台作业
将后台作业提至前台
fg 1(作业号)
区别验证
fork出一个子进程后,如果将父进程退出,则前台作业结束
子进程会以后台进程的身份继续运行
此时,我们用Ctrl+C无法终止该子进程(因为CTRL+C只可以终止前台作业)
3.会话 (session)
会话是一个或多个进程组的集合。
一个会话可以有一个控制终端,这通常是登录到其上的的终端设备(在终端登录情况下)或伪终端设备(在网络登录情况下)
建立与控制终端连接的会话首进程被称为控制进程,
一个会话中的进程组可被分为一个前台进程组或一个或多个后台进程组(前台进程组只有一个)
所以一个会话中要包括一个控制进程,一个前台进程组或和任意多个后台进程组
打开一个终端即新建立一个会话的过程。关闭一个终端,即关闭一次会话 ,其中所有的作业,进程组都不存在了。
终端
终端的基本概念
在UNIX系统中,用户通过终端登录系统后得到一个Shell进程,这个终端成为Shell进程的控制终端 (Controlling Terminal)
控制终端是保存在PCB中的信息,而我们知道fork会复制PCB中的信息,因此由Shell进程启动的其它进程的控制终端也是这个终端。
默认情况 下(没有重定向)
每个进程的标准输入、标准输出和标准错误输出都指向控制终端,进程从标准输入读也就是读用户的键盘输入,进程往标准输出或标准错误输出写也就是输出到显示器上。
此外在控制终端输入一些特殊的控制键可以给前台进程发信号,例如Ctrl-C表示SIGINT,Ctrl-\表示SIGQUIT。
如何查看终端
每个进程都可以通过一个特殊的设备文件/dev/tty访问它的控制终端。 ttyname函数可以由文件描述符查出对应的文件名,该文件描述符必须指向一个终端设备而不 能是任意文件。
4.守护进程
4.1:概念及作用
守护进程也叫精灵进程,是一种运行在后台的特殊进程
特点:
独立于控制终端并且周期性运行某种任务或等待处理某些发生的事件
因为没有控制终端所以无法和用户交互
不受用户登录和注销的影响
作用
守护进程是一种很有用的进程,满足于特殊的进程需求
比如:Linux大多数服务器就是守护进程
4.2:查看守护进程
ps axj | more查看守护进程
参数a代表列出所有用户进程
参数x代表列出有无控制终端的进程
参数j代表列出与作业控制相关的信息
在这里插入图片描述

3.进程间通信(IPC)
进程用户空间是相互独立的,一般而言是不能相互访问的。但很多情况下进程间需要互相通信,来完成系统的某项功能。进程通过与内核及其它进程之间的互相通信来协调它们的行为。
进程通信的目的
数据传输
一个进程需要将它的数据发送给另一个进程,发送的数据量在一个字节到几M字节之间
共享数据
多个进程想要操作共享数据,一个进程对共享数据
通知事
一个进程需要向另一个或一组进程发送消息,通知它(它们)发生了某种事件(如进程终止时要通知父进程)。
资源共享
多个进程之间共享同样的资源。为了作到这一点,需要内核提供锁和同步机制。
进程控制
有些进程希望完全控制另一个进程的执行(如Debug进程),此时控制进程希望能够拦截另一个进程的所有陷入和异常,并能够及时知道它的状态改变。
linux使用的进程间通信方式
管道(pipe)
管道包括三种:
普通管道PIPE: 通常有两种限制,一是单工,只能单向传输;二是只能在父子或者兄弟进程间使用.
流管道s_pipe: 去除了第一种限制,为半双工,只能在父子或兄弟进程间使用,可以双向传输.
命名管道:name_pipe:去除了第二种限制,可以在许多并不相关的进程之间进行通讯.命名管道通常被称为FIFO,
它作为特殊的设备文件存在于文件系统中。因此,在进程中可以使用open()和close()函数打开和关闭命名管道。 通过命令创建mkfifo filename 也可通过函数创建
通过在内核中创建一块缓冲区 内核间开辟的缓冲区大小为4K
数据结构为一个环形队列(有效避免数据溢出 节省空间) 可以通过文件描述符或者管道描述符实现对管道的读写操作

一般而言,进程退出,管道释放,所以管道的生命周期跟随进程。
信号(signal)
对于 Linux来说,实际信号是软中断,许多重要的程序都需要处理信号。
信号的名字和编号:
每个信号都有一个名字和编号,这些名字都以“SIG”开头,例如“SIGIO ”、“SIGCHLD”等等。
信号定义在signal.h头文件中,信号名都定义为正整数。
具体的信号名称可以使用kill -l来查看信号的名字以及序号,信号是从1开始编号的,不存在0号信号。kill对于信号0又特殊的应用。
在这里插入图片描述
信号的处理:
Unix经典信号不支持排队
(内核)信号向下传递 kernelsend sigin->PCB–>未决信号集----->屏蔽信号集(阻塞)—>handler ------进行信号处理
信号的处理有三种方法,分别是:忽略、捕捉和默认动作
忽略信号,大多数信号可以使用这个方式来处理,但是有两种信号不能被忽略(分别是 SIGKILL和SIGSTOP)。因为他们向内核和超级用户提供了进程终止和停止的可靠方法,如果忽略了,那么这个进程就变成了没人能管理的的进程,显然是内核设计者不希望看到的场景
捕捉信号,需要告诉内核,用户希望如何处理某一种信号,说白了就是写一个信号处理函数,然后将这个函数告诉内核。当该信号产生时,由内核来调用用户自定义的函数,以此来实现某种信号的处理。
系统默认动作,对于每个信号来说,系统都对应由默认的处理动作,当发生了该信号,系统会自动执行。不过,对系统来说,大部分的处理方式都比较粗暴,就是直接杀死该进程。
具体的信号默认动作可以使用man 7 signal来查看系统的具体定义。
对于信号来说,最大的意义不是为了杀死信号,而是实现一些异步通讯的手段,那么如何来自定义信号的处理函数呢?
信号捕捉实际操作流程:
1.定义初始化信号行为结构体 struct sigaction act
act.sa_handler=选择信号行为
void*(sa_handler)(int)//根据要求定义捕捉函数
act.sa_flags=0 //根据捕捉函数接口调整flags
act.sa_mask //临时屏蔽字 预防多个信号绑定同一个捕捉函数 实现造成资源访问的问题
2.定义和实现捕捉函数
3.将自定义信号替换为默认行为 sigaction()
进程通常工作于用户层 当信号到达进程抵达内核层无法实现实时处理只有进程切换到内核空间 可以检测到待处理信号并进行处理
消息队列
消息队列是消息的链接表,包括Posix消息队列system V消息队列。有足够权限的进程可以向队列中添加消息,被赋予读权限的进程则可以读走队列中的消息。消息队列克服了信号承载信息量少,管道只能承载无格式字节流以及缓冲区大小受限等缺点。
特点
消息队列是面向记录的,其中的消息具有特定的格式以及特定的优先级。
消息队列独立于发送与接收进程。进程终止时,消息队列及其内容并不会被删除。
消息队列可以实现消息的随机查询,消息不一定要以先进先出的次序读取,也可以按消息的类型读取。
内存共享映射
Linux下的进程间通信也可以使用mmap的内存共享映射来实现,mmap的作用就是把磁盘文件的一部分直接映射到进程的内存中,那么进程就可以直接对该内存文件进行操作,mmap也设置了两种机制:共享和私有,如果是共享映射,那么在内存中对文件进行修改,磁盘中对应的文件也会被修改,相反,磁盘中的文件有了修改,内存中的文件也被修改。如果是私有映射,那么内存中的文件是独立的,二者进行修改都不会对对方造成影响。通过这样的内存共享映射就相当于是进程直接对磁盘中的文件进行读写操作一样,那么如果有两个进程来mmap同一个文件,就实现了进程间的通信。磁盘中的文件通过mmap函数来实现映射,然后通过munmap函数取消映射。先来看一下函数的原型:
#include <sys/mman.h>
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
int munmap(void *addr, size_t length);
其中对于mmap来说,有6个参数,第一个参数是你要映射的起始地址,这里一般用NULL,这样系统会在0地址附近随机分配一块内存。第二个参数是所要映射的文件长度。第三个参数是所映射的文件的权限,其中包含(PROT_EXEC, PROT_READ, PROT_WRITE, PROT_NONE)这四种参数。第四个参数是映射类型,其中包括(MAP_SHARED, MAP_PRIVATE)。第五个参数是文件描述符。第六个参数是偏移量。我们可以看到函数的返回值为void *,那么如果映射成功则会返回映射的首地址,如果出错则返回常数MAP_FAILED。当进程终止时,该进程的映射内存会自动解除,也可以调用munmap解除映射,解除成功返回0,出错返回-1。
网络套接字(socket)
利用网络进行通信,与前面所提到的通信方式不同的是,它能用于不同计算机之间的不同进程间通信。
各种通信方式的比较和优缺点
管道:速度慢,容量有限,只有父子进程能通讯
FIFO:任何进程间都能通讯,但速度慢
消息队列:容量受到系统限制,且要注意第一次读的时候,要考虑上一次没有读完数据的问题
共享内存区:能够很容易控制容量,速度快,但要保持同步,比如一个进程在写的时候,另一个进程要注意读写的问题,相当于线程中的线程安全,当然,共享内存区同样可以用作线程间通讯,不过没这个必要,线程间本来就已经共享了同一进程内的一块内存。当共享文件过大可以通过文件切片映射

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值