浅浅浅浅浅谈 -进程 --Linux

  • 并发 和 并行

首先先来说一说这个刚了解到的概念,并发(concurrent)&并行(parallel)。

“时间片轮转进程调度算法”–并发意味着:当多个线程在操作的时候,系统CPU只有一个,那么多个线程根本不可能同时运行,CPU只能把运行时间分化成很多很短的时间段,再依次分配给正在运行的线程,在其中一个线程运行的过程中其他线程都处于挂起状态。
并行 :一个系统有多个CPU时,多个线程的运行可能是非并发的,其他的CPU在同一时间可以运行其他线程,其互相不冲突,不抢占CPU资源。

  • 在并发环境中,多线程的运行做不到真正的节省时间、充分的利用CPU,只是在很小的时间段中不停地 |挂起|–|执行|–|挂起|,给用户一种每个线程都在运行的错觉,这个时候多线程程序的优点只有:改善系统的响应性能、提高程序的友好性。
  • 在并行环境中,一时刻允许运行多个线程,这时多线程程序才真正充分利用了CPU的处理能力,此时多线程能发挥它更大的优势:充分利用CPU、节省时间、改善响应性能和增加程序的友好性。

贴近生活一点来讲就是:

你同时点了炸鸡、奶茶还有蛋糕的外卖,并发就是你一个人同时吃掉炸鸡、奶茶、蛋糕并行就是你喊两个小伙伴一起来同时吃掉炸鸡、奶茶、蛋糕

  • 进程


进程是指在系统中正在运行的一个应用程序,程序一旦运行就是进程,也可以认为是程序运行的一个实例。

进程是系统进行资源分配的独立实体,每个进程都有独立的地址空间,所以一个进程不能直接访问其他进程的变量等,要通过进程间的通信来实现,比如说:管道、文件等。

每个进程都是通过唯一的进程ID进行标识的,进程ID是一个非负数,当然进程还有其他的一些表示信息可以通过相应的函数获得。(父进程ID、进程实际组、进程有效组…)

进程的构成:

代码段数据段堆栈段
  • fork() & vfork()

  • fork ork创造的子进程是父进程的完整副本,复制了父亲进程的资源,包括内存的内容task_struct内容

  • vfork vfork创建的子进程与父进程共享数据段,而且由vfork()创建的子进程将先于父进程运行(确切的说vfork创建出来的是轻量级进程,也叫线程,是共享资源的进程。

    vork 如果子进程改变了变量值,而父进程中相同的变量值不会改变,子进程与父进程该变量的虚拟地址是相同的,但在内核中被映射的物理地址不同。

    写时复制 :子进程复制了父进程的结构体,系统堆栈空间和页面表,所以说在使用了fork系统调用创建子进程后,如果子进程中的变量没有发生变化之前,子进程和父进程中该变量指向的是同一块内存。但是一旦子进程改变了该变量(写操作),就会通过写入时复制的方法为有关的页面建立一个新的副本。
    @:写入时复制是一个被使用在程式设计领域的最佳化策略。其基础的观念是,如果有多个呼叫者同时要求相同资源,他们会共同取得相同的指标指向相同的资源,直到某个呼叫者尝试修改资源时,系统才会真正复制一个副本(private copy)给该呼叫者,以避免被修改的资源被直接察觉到,这过程对其他的呼叫只都是通透的。此作法主要的优点是如果呼叫者并没有修改该资源,就不会有副本被建立。

vfork 该系统调用相对fork更加直接,创建的子进程直接共享了父进程的虚拟空间,也一并继承了父进程的物理空间。
也就是说如果在此时的子进程中改变某变量的值,父进程中的该变量值也同样发生变化。

  • 由vfork创造出来的子进程还会导致父进程挂起,除非子进程exit或者execve才会唤起父进程
  • 由vfork创建出来得子进程不应该使用return返回调用者,或者使用exit()退出,但是它可以使用_exit()函数来退出
  • 由vfok创建出来的子进程共享了父进程的所有内存,包括栈地址,直至子进程使用execve启动新的应用程序为止

!:如果要使用return来退出就会出现逻辑混乱的重复vfork的状态。在子进程使用return之后返回到了调用处,所以直接导致父进程再次创建出一个新的vfork进程。所以要使子进程运行结束之后返回父进程就不能用return返回,要调用exit或_exit。

exit & _exit

#include <stdlib.h>
void exit(int status);
void _Exit(int status);

#include <unistd.h>
void _exit(int status);
  • exit :是一个C库标准函数。此函数执行会首先调用由 atexit注册的函数,然后执行关闭所有标准IO流,刷新流缓冲区等操作。对于常用的有返回值的 return 调用,相当于调用了 exit 。如 return(0)== exit(0);
  • _exit : 是一个系统调用。此函数不会调用 atexit 注册的函数,也不会运行信号处理程序。对标准IO流的缓冲区是否进行刷新取决于该函数在系统中的实现。一般UNIX下不会刷新。 exit函数会调用此函数.(在windows下的_exit函数会对标准IO流的缓冲进行刷新)
  • _Exit : 是一个C库标准函数。其动作类似 _exit 。

好了,创建子进程之后我们来看看进程的状态,孤儿进程&僵尸进程:

孤儿进程 :一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作。

每当出现一个孤儿进程,内核就把孤儿进程的父进程设置为init,init进程就会循环地wait()这些子进程,在这里孤儿进程就正式的结束了生命。所以就此来看孤儿进程对系统来说并没有什么太大的危害。
僵尸进程 :一个进程使用fork创建子进程,如果子进程退出,而父进程并没有调用wait或waitpid获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中。这种进程称之为僵尸进程。

在linux中要保证只要父进程想知道子进程结束时的状态信息就可以得到,所以在每个进程退出的时候,内核是释放该进程所占用的大部分资源,但还是保留一定信息,比如说进程号,退出状态等等,一直要等到父进程调用wait或waitpid才进行释放。

问题也出现在这,如果父进程不调用wait那么进程号等信息就会一直存在占用系统空间,但系统所能使用的进程号是有限的,如果有大量的僵尸进程堆积就会造成操作系统不能产生新的进程号,所以我们要尽量避免僵尸进程出现在系统中。

  • 通过百度呢,知道了两种僵尸进程的解决办法
    1> 通过信号机制:
    子进程退出时向父进程发送SIGCHILD信号,父进程处理SIGCHILD信号。在信号处理函数中调用wait进行处理僵尸进程。
    2> fork两次:
    就是将子进程成为孤儿进程,从而其的父进程变为init进程,通过init进程可以处理僵尸进程。

  • 在《Linux C编程实战》7.2.2 中知道了如何创建一个守护进程,但是守护进程与后台进程有什么区别呢?
    守护进程与后台进程主要有一下三点大的区别:
  1. 守护进程已经完全脱离终端控制台了,而后台程序并未完全脱离终端(在终端未关闭前还是会往终端输出结果)。
  2. 守护进程在关闭终端控制台时不会受影响,而后台程序会随用户退出而停止,需要在命令还末尾加上’&'才能避免影响。
  3. 守护进程的会话组和当前目录,文件描述符都是独立的。后台运行只是终端进行了一次fork,让程序在后台执行,这些都没改变。

守护进程:在后台运行的一种特殊进程,它脱离于终端,从而这可避免进程被任何终端所产生的信号打断,它在执行进程中的产生信息也不在任何终端上显示。守护进程周期性地执行某种任务或等待处理某些发生的事件,Linux的大多数服务器就是用守护进程实现的。

后台进程

  1. command & : 后台运行,你关掉终端会停止运行
  2. nohup command & : 后台运行,你关掉终端也会继续运行

在Linux中如果你发现此时台前运行的一个程序需要很长时间,但你有需要去做其他事情就可以用Ctrl+Z,将这个程序挂起(该程序在后台中暂停)

然后就可以调度到后台继续执行bg 1(编号)、 jobs 查看正在运行的任务、fg 1(编号) 把编号为1的程序调回到台前执行、&将指令放在后台继续执行。

Linux中,当在前台运行某个作业时,终端被该作业占据;而在后台运行作业时,它不会占据终端。可以使用&命令把作业放到后台执行。实际上,这样是将命令放入到一个作业队列中了。

如果后台执行的指令需要输出一些信息,那么这些正常的输出一样会出现在终端上干扰你正在运行的其他程序或者正在做的其他事情,这个时候输出重定向命令就显得格外重要了,想要不被干扰就可以将后台执行的指令的输出冲定向到某个文件中,最好是标准错误输出也进行重定向输出,这样就可以专心做其他事情啦!

  • 杀死进程
    要结束一个进程首先要知道该进程的明确信息:进程PID,(使用ps -ef命令),最安全的方法就是单纯的使用kill命令:
# kill -pid

**!!**但一定要注意:标准的kill命令通常都能达到目的。终止有问题的进程,并把进程的资源释放给系统。然而,如果进程启动了子进程,只杀死父进程,子进程仍在运行,因此仍消耗资源。为了防止这些所谓的“僵尸进程”,应确保在杀死父进程之前,先杀死其所有的子进程。

还有更厉害一点的:给父进程发送一个TERM信号,以为着想要结束它以及它的子进程。

# kill -TERM PPID

好了,创建的进程被结束了,这次的小总结也就到这里啦~

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值