进程基础

进程的概念

在这里插入图片描述

在这里插入图片描述

进程类型

在这里插入图片描述

进程状态

在这里插入图片描述

进程状态图

在这里插入图片描述

进程信息查询和相关命令

查看进程信息

ps —查看系统进程
top —查看进程动态信息
/proc —查看进程详细信息

进程相关命令
nice —按用户指定的优先级运行程序
renice —改变正在运行进程的优先级
jobs —查看后台进程
bg —将挂起的进程在后台运行
fg —把后台运行的程序放到前台运行

进程相关函数

创建进程

#include  <unistd.h>
 pid_t  fork(void);
 
	创建新的进程,失败时返回-1
	成功时父进程返回子进程的进程号,子进程返回0
	通过fork的返回值区分父进程和子进程

示例

id_t  pid;

  if ((pid = fork()) < 0) {
     perror(“fork”);  
     return -1;
  }
  else  if (pid == 0) {
     printf(“child  process :  my pid  is %d\n”, getpid());
  }
  else {
     printf(“parent  process :  my pid  is  %d\n”, getpid());
  }  

父子进程

  • 子进程继承了父进程的内容
  • 父子进程有独立的地址空间,互不影响
  • 若父进程先结束
    • 子进程成为孤儿进程,被init进程收养
    • 子进程变成后台进程
  • 若子进程先结束
    • 父进程如果没有及时回收,子进程变成僵尸进程

进程结束

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

	结束当前的进程并将status返回
	exit结束进程时会刷新()缓冲区

exec函数族

    用fork函数创建新进程后,经常会在新进程中调用exec函数去执行另外一个程序。当进程调用exec函数时,该进程被完全替换为新程序。调
	用exec函数并不创建新进程,所以前后进程的ID并没有改变。
功能:
  在调用进程内部执行一个可执行文件。可执行文件既可以是二进制文件,也可以是任何Linux下可执行的脚本文件。
函数族:
	execl, execlp, execle, execv, execvp, execvpe
  • 进程调用exec函数族执行某个程序

  • 进程当前内容被指定的程序替换

  • 实现让父子进程执行不同的程序
     父进程创建子进程
     子进程调用exec函数族
     父进程不受影响

进程–execl/execlp

execl和execlp的区别在于第一个参数,execl指定路径位置、execlp在PATH里面查找

#include  <unistd.h>
  int execl(const char *path, const char *arg,);
  int execlp(const char *file, const char *arg,);
 
	 成功时执行指定的程序;失败时返回EOF
	 path   执行的程序名称,包含路径
	 arg…  传递给执行的程序的参数列表
	 file   执行的程序的名称,在PATH中查找

执行ls命令,显示/etc目录下所有文件的详细信息

  if  (execl(/bin/ls”, “ls”,-a”,-l”,/etc”, NULL) < 0) {
     perror(“execl”);
  }  
  
  if  (execlp(“ls”, “ls”,-a”,-l”,/etc”, NULL) < 0) {
     perror(“execlp”);
  }  

进程–execv/execvp

execv和execl区别:把execl第一个参数后面的参数放入数组中

 #include  <unistd.h>
  int execv(const char *path, char *const argv[]);
  int execvp(const char *file, char *const argv[]);

	 成功时执行指定的程序;失败时返回EOF
	 arg… 封装成指针数组的形式

执行ls命令,显示/etc目录下所有文件的详细信息

  char  *arg[] = {“ls”,-a”,-l”,/etc”, NULL};
  
  if  (execv(/bin/ls”, arg) < 0) {
     perror(“execv”);
  }  
  
  if  (execvp(“ls”, arg) < 0) {
     perror(“execvp”);
  }  

进程–system()函数

system()会调用fork()产生子进程,由子进程来调用/bin/sh-c string来执行参数string字符串所代表的命令,此命令执行完后随即返回原调用的进程。在调用system()期间SIGCHLD 信号会被暂时搁置,SIGINT和SIGQUIT 信号则会被忽略。

与exec的区别

1、system()和exec()都可以执行进程外的命令,system是在原进程上开辟了一个新的进程,但是exec是用新进程(命令)覆盖了原有的进程
2、system()和exec()都有能产生返回值,system的返回值并不影响原有进程,但是exec的返回值影响了原进程
3.exec函数执行完后会结束子进程,system则是阻塞调用结束后返回子进程

#include  <stdlib.h>
  int system(const char *command);
  
	 成功时返回命令command的返回值;失败时返回EOF
	 当前进程等待command执行结束后才继续执行

范例:

#include<stdlib.h>
main()
{
system("ls -al /etc/passwd /etc/shadow");

char tmp[];
sprintf(tmp,"/bin/mount -t vfat %s /mnt/usb",dev);
system(tmp);
}

僵尸进程处理方法

如何找出僵尸进程?

打开终端并输入下面命令:

ps aux | grep Z

会列出进程表中所有僵尸进程的详细内容。

*方法一:wait/waitpid函数:pid_t wait(int status)

父进程在调用wait函数之后就可以将自己阻塞,由wait自动分析是否当前进程的某个子进程已经退出,如果让它找到了这样一个已经变成僵尸的子进程,wait就会收集这个子进程的信息,并把它彻底销毁后返回;如果没有找到这样一个子进程,wait就会一直阻塞在这里,直到有一个出现为止。其中的参数status用来保存被收集进程退出时的一些状态,它是一个指向int类型的指针。但如果我们对这个子进程是如何死掉的毫不在意,只想把这个僵尸进程消灭掉,(事实上绝大多数情况下,我们都会这样想),我们就可以设定这个参数为NULL,就象下面这样:
pid = wait(NULL);
在原代码中的父进程块中也只需要添加 wait(NULL),再运行的时候就会发现僵死进程已经被处理掉了。但是,这么做的缺点也很明显。在阻塞的过程中,父进程停止了自己的运行。在实际应用中我们不可能为了处理一个僵死进程而令父进程一直wait。并且一个wait函数只能处理一个僵死进程,作用十分有限。

方法二:将父进程中对SIGCHLD信号的处理函数设为SIG_IGN(忽略)

需要信号的头文件:signal.h。只需要在父进程块中加入一行代码:signal(SIGCHLD,SIG_IGN);就可以不产生僵死进程。调用这个signal函数就定义了父进程对子进程结束后返回的SIGCHLD信号的响应方式:忽略。
方法三:原理是将子进程成为孤儿进程,从而其的父进程变为init进程,通过init进程可以处理僵尸进程。在一个子进程中在创建一个子进程,让父进程去waitpid僵尸进程。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值