Linux_进程控制

一.进程相关操作

1.进程创建

#include <unistd.h>
pid_t fork(void);
返回值:子进程中返回0,父进程返回子进程id,出错返回-1

2.进程等待

进程等待的必要性:

1.子进程退出, 如果父进程不管, 会成为僵尸进程, 造成资源泄漏

2.进程一旦变成僵尸进程, 不能被 kill

3.父进程需要知道子进程运行完成的返回

4.父进程通过进程等待的方式,回收子进程资源,获取子进程退出信息

进程等待的方法:  wait()  waitpid()

wait() 和 waitpid() 中传出参数 status保存了进程的退出状态, 不能简单的当作整形来看待,
可以借助系统提供的宏判断终止的具体原因

1. WIFEXITED(status)  != 0 进程正常退出
   WEXITSTATUS(status) 获取进程退出状态

2. WIFSIGNALED(status) != 0 进程异常终止
   WTERMSIG(status)     取得使进程终止的信号编号
#include<sys/types.h>
#include<sys/wait.h>
pid_t wait(int*status);

功能:
1.阻塞等待子进程退出 2.回收子进程资源  3.获取子进程结束状态
返回值:
成功返回被等待进程pid,失败返回-1。
参数:
输出型参数,获取子进程退出状态,不关心则可以设置成为NULL
 
// wait() 使用

int main(){
  pid_t ret = fork();     // 创建进程
  if (ret == -1){                                                                                
    perror("fork() error");
    return 1;
  } else if (ret == 0){
    printf("child[%d] sleeping\n", getpid());
    sleep(20);                                  
    return 3;
  } else {
    sleep(2);
    int status;
    pid_t wait_ret = wait(&status);   // 父进程阻塞等待子进程
    if (wait_ret == -1){
      perror("wait() error");
      return 1;
    }
    if (WIFEXITED(status)){   //子进程正常退出
      printf("child[%d] eixt code: %d\n", wait_ret, WEXITSTATUS(status));
    }
    if (WIFSIGNALED(status)){ //子进程收到信号退出
      printf("child[%d] signal code: %d\n", wait_ret, WTERMSIG(status));                         
    }
  }
  return 0;
}
pid_ t waitpid(pid_t pid, int *status, int options);
返回值:
    当正常返回的时候waitpid返回收集到的子进程的进程ID;
    如果设置了选项WNOHANG,而调用中waitpid发现没有已退出的子进程可收集,则返回0;
    如果调用中出错,则返回-1,这时errno会被设置成相应的值以指示错误所在;
参数:
    pid:
        Pid=-1,等待任一个子进程。与wait等效。
        Pid>0.等待其进程ID与pid相等的子进程。
status:
        传出参数

options:
        0      : 阻塞
        WNOHANG: 非阻塞

 

// 父进程 回收三个子进程: 1. 调用 ls -a  2.调用 add 3.执行段错误程序

int main(){
  pid_t pid;

  int i = 0;
  for ( ; i < 3; i++){
    pid = fork();
    if (pid == 0){ 
      break;
    }   
  }
  
  if (i == 0){ 
    execlp("ls", "ls", "-a", NULL);
  } else if (i == 1){
    execl("add", "add", NULL);    
  } else if (i == 2){
    execl("err", "err", NULL);
  } else {
    int status;
    int ret;                                                                                     
    int n = 3;
    do{
      ret = waitpid(-1, &status, WNOHANG); // 父进程调用 waitpid() 非阻塞等待三个子进程
      if (ret == -1){
        perror("waitpid() error\n");
        return -1;
      } else if (ret == 0){
        sleep(1);
        continue;
      } else {
        n--;
        printf("回收子进程: %d\n", ret);
        if (WIFEXITED(status)){
          printf("子进程正常返回值: %d\n", WEXITSTATUS(status));
        }
        if (WIFSIGNALED(status)){
          printf("子进程收到信号退出: %d\n", WTERMSIG(status));
        }                                                                                        
      }
    }while(n > 0);
  }
  printf("finish\n");                                                                            
  return 0;
}

 

3.进程终止

正常退出:(可通过echo $? 查看退出码)

    1._exit()   直接退出

    2.exit()     执行清理函数, 刷新缓冲,关闭流,  调用_exit()

    3.return n   等同于调用  exit(n)

异常退出:

    cltr + c, 信号终止

 所以进程执行完后最好使用exit()或return终止进程

二.程序替换(exec函数)

1.替换原理

用 fork() 创建子进程后执行和父进程相同的代码段(有可能执行不同的代码分支), 子进程可以调用一种exec函数以执行另一个程序  当进程调用一种exec函数时, 该进程的用户空间代码段和数据被新程序完全替换, 从新程序启动例程开始执行

因为调用exec不创建新进程, 只是替换了代码段, 所以进程的id并不变

2. exec函数

返回值: 这些函数调用成功, 替换代码从新程序启动代码开始执行, 不返回
             调用失败返回 -1

#include <unistd.h>


int execl(const char *path, const char *arg, ...);  
// file: 要加载的程序名 函数去PATH中搜索file, 没有找到报错  常用于调用系统程序: ls, cat, cp
int execlp(const char *file, const char *arg, ...); 

int execle(const char *path, const char *arg, ...,char *const envp[]);

int execv(const char *path, char *const argv[]);

int execvp(const char *file, char *const argv[]);

int execve(const char *path, char *const argv[], char *const envp[]);

//exec函数规律:
l: list   参数使用列表
v: vector 参数使用数组
p: PATH   搜索环境变量PATH
e: env    表示自己维护的环境变量

execve是真正的系统调用,其它五个函数最终都调用 execve 

使用方法:

// 执行 ls -la 命令

execlp("ls", "ls", "-la", NULL); // NULL表示参数结束  p表示PATH, 无需写全路径, 自动去PATH找
execl("/bin/ls", "ls", "-la", NULL); // 不带 p 要写替换程序的路径

char *const args[] = {"ls", "-la", NULL}; // 使用数组做参数, 要构造一个数组
execv("/bin/ls", args);
execvp("ls", args);

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值