Linux 进程

进程

  • 有代码的就是程序,正在跑的程序就是进程。
  • 几个重要的linux 查看进程的命令需要记忆!
    • Ps命令, P是progcess(进程的意思),s是status(状态的意思),ps 就是查看进程状态。
    • Ps -ef
    • Ps aux
    • ps ax 0 pid ppid…
    • ps-ef | grep 关键字

常用的函数

atexit()

  • int atexit(void (*function)(void));
    • 功能: 向内核登记终止函数,类似于return或者exit
    • 返回: 若成功则为0 ,若出错则为-1
    • 每个启动的进程都默认登记了一个标准的终止函数
    • 终止函数在进程终止时释放进程所占用的一些资源
    • 登记的多个终止函数执行顺序是以栈的方式执行,先登记的后执行。
内核returnexit()_exit() / _Exit()
I/O缓存YYN
调用终止函数YYN

进程资源限制getrlimit()

  • 资源限制的修改规则
    • 硬资源限制必须大于等于软资源限制
    • 任何一进程可以降低或者提升其软资源限制、但必须小于等于其硬资源限制。
    • 任何一进程可以降低其硬件资源限制,但必须大于其软限制,普通用户不可逆此操作。
    • 只有超级用户可以提高硬限制

  • int getrlimit(int resource, struct rlimit *rlptr);
    • 功能: 获得资源限制,存放在rlptr 指向的结构体中
    • 返回: 成功返回0 ,出错返回非0

  • int setrlimit(int resource, const struct rlimie *rlptr);
    • 功能: 通过rlptr 指向的结构体去修改resource 指定的资源限制
    • 返回: 成功返回0 ,出错返回非0

  • resource取值
    • RLIMIT_AS 进程可用存储区大小
    • RLIMIT_CORE core文件最大字节数
    • RLIMIT_CPU CPU时间最大值
    • RLIMIT_DATA 数据段最大长度
    • RLIMIT_FSIZE 可创建文件的最大长度
    • RLIMIT_LOCKS 文件锁的最大数
    • RLIMIT_MEMLOCK 使用mlock能否在存储器中锁定的最长字节数
    • RLIMIT_NOFILE 能打开的最大文件数
    • RLIMIT_NPROC 每个用户ID可拥有的最大子进程数.
    • RLIMIT_RSS 最大驻内存集的字节长度
    • RLIMIT_STACK 栈的最大长度

进程标识getpid()

  • pid_t getpid(void) : 获得当前进程ID
  • uid_t getuid(void) : 获得当前进程的实际用户ID
  • uid_t geteuid(void) : 获得当前进程的有效用户ID
  • gid_t getgid(void) : 获得当前进程的用户组ID
  • pid_t getppid(void) : 获得当前进程的父进程ID
  • pid_t getpgrp(void) : 获得当前进程所在的进程组ID
  • pid_t getpgid(pid_t pid) :获得进程ID 为pid 的进程所在的进程组ID

进程创建fork()

  • fork创建的新进程被称为子进程,该函数被调用一次,但返回两次。两次返回的区别是: 在子进程中的返回值是0,而在父进程中的返回值则是新子进程的进程ID。
  • 创建子进程,父子进程哪个先运行根据系统调度且复制父进程的内存空间。
    • 子进程的继承属性:用户信息和权限、目录信息、信号信息、环境、共享存储段、资源
      限制、堆、栈和数据段,共享代码段。
    • 子进程特有属性:进程ID、锁信息、运行时间、未决信号
    • 子进程只继承父进程的文件描述表,不继承但共享文件表项和i-node。
  • vfork创建子进程,但子进程先运行且不复制父进程的内存空间。

  • pid_t fork(void);

    • 返回:子进程中为0 ,父进程中为子进程ID ,出错为-1
  • pid_t vfork(void);

    • 返回:子进程中为0 ,父进程中为子进程ID ,出错为-1

wait函数

  • pid_t wait(int *status);
    • 功能: 等待子进程退出并回收,防止僵尸进程产生
    • 返回: 成功返回子进程ID ,出错返回-1

  • pid_t waitpid(pid_t pid, int *status, int options);
    • 功能: wait 函数的非阻塞版本
    • 返回: 成功返回子进程ID ,出错返回-1

  • status参数:为空时,代表任意状态结束的子进程,若不为空,则代表指定状态结束的子进程。
  • wait和waitpid函数区别
    • 在一个子进程终止前,wait使其调用者阻塞
    • waitpid有一选择项,可使调用者不阻塞。
    • waitpid等待一个指定的子进程,而wait等待所有的子进程,返回任一终止子进程的状态。
  • 检查wait和waitpid函数返回终止状态的宏
    • WIFEXITED/WEXITSTATUS(status):若为正常终止子进程返回的状态,则为真。
    • WIFSIGNALED/WTERMSIG(status):若为异常终止子进程返回的状态,则为真(接到一个不能捕捉的信号)
    • WIFSTOPED/WSTOPSIG(status):若为当前暂停子进程的返回的状态,则为真。
  • options参数
    • WNOHANG:若由pid指定的子进程没有退出则立即返回,则waitpid不阻塞此时其返回值为0。
    • WUNTRACED:若某实现支持作业控制,则由pid指定的任一子 进程状态已暂停,且其状态自暂停以来还未报告过,则返回其状态。
  • waitpid函数的pid参数
    • pid == -1 :等待任一子进程,功能与wait等效。
    • pid > 0 :等待其进程ID与pid相等的子进程
    • pid == 0 :等待其组ID等于调用进程的组ID的任一子进程
    • pid < -1 :等待其组ID等于pid的绝对值的任一子进程

exec函数

当进程调用一种exec函数时,该进程完全由新程序代换,替换原有进程的正文,而新程序则从其main函数开始执行。因为调用exec并不创建新进程,所以前后的进程ID并未改变。exec只是用另一个新程序替换了当前进程的正文、数据、堆和栈段。

  • int execl(const char pathname, const char *arg0,…/(char )0/);
  • int execv(const char pathname, char *const argv[]);
  • int execle(const char pathname, const char *arg0,… /(char )0, char *const envp[]/);
  • int execve(const char pathname, char *const argv[], char *const envp[]);
  • int execlp(const char pathname, const char *arg0,…/(char )0/);
  • int execvp(const char *pathname, char *const argv[]);
    • 返回:出错返回-1,成功则不返回
  • exec系列函数的注意点
    • execve函数为系统调用,其余为库函数。执行execve函数后面的代码不执行。
    • execlp和execvp函数中的pathame,相对和绝对路径均可使用,其它四个函数中的 pathname只能使用绝对路径。相对路径一定要在进程环境表对应的PATH中。
    • argv参数为新程序执行main函数中传递的argv参数,最后一个元素为NULL。
    • envp为进程的环境表

system 函数

  • int system(const char *command);
    • 功能:简化exec
    • 返回:成功返回执行命令的状态, 出错返回-1

常用函数代码示例

环境表

  • extern char **environ
    • 每个进程都有一个独立的环境表
    • 初始的环境表继承自父进程
  • 获得环境表信息案例
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
extern char **environ;
int main(int argc, char *argv[]){
  int i = 0;
  char *ptr = environ[i];
  while(ptr != NULL){
    printf("%s\n", ptr);
    ptr = environ[++i];
  }
  return 0;
}
  • 环境变量操作函数

    • char *getenv(const char *name);
    • 功能: 获取环境变量值
    • 返回: 指向与name 关联的value 的指针, 若未找到则返回NULL。

  • int putenv(char *str);
    • 功能: 形式为name = value的字符串,将其放到环境表中。如果name 已经存在,则先删除其原来的定义。
    • 返回: 成功返回0, 出错返回非-1

  • int setenv(const char *name, const char *value, int rewrite);
    • 功能: 将name 设置为value 。如果在环境中name已经存在,那么若rewrite 非0,则首先删除其现存的定义,若rewrite 为0 ,则不删除其现存定义(name不设置为新的value ,而且也不出错) 。
    • 返回: 成功返回0, 出错返回非-1

  • int unsetenv(const char *name);
    • 功能: 删除name 的定义,即使不存在这种定义也不算出错。
    • 返回: 成功返回0, 出错返回非-1

fork函数代码示例

子父进程区别与wait()函数测试
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
int main(void)
{
  printf("%d\n",getpid());
  int a = 0,i = 0;
  int pid1 = fork();
  if(pid1 == 0){
    a=10;
    for(i=0 ; i < 3 ; ++i){
      printf("我是子进程:%d\n",getpid());
      sleep(1);
    }
 // while(1);
    return 20;
  }
  else if(pid1 > 0){
    printf("a:%d",a);
    int val = 0;
    for(i=0 ; i < 5 ; ++i){
      printf("我是父进程:%d\n",getpid());
      sleep(1);
    }
    if(wait(&val) == -1){
      printf("子进程回收失败\n");
      exit(-1);
    }
    if(WIFSIGNALED(val)){
      printf("进程异常终止\n");
    }
    else{
      printf("正常结束\n");
    }
    printf("子进程的返回值:%d\n",WEXITSTATUS(val));
    printf("val:%#o\n",val);
  }
  else{
    perror("创建进程失败\n");
    exit(-1);
  }
  return 0;
}
孤儿进程和僵尸进程示例
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <string.h>
int main(void)
{
  int i = 0;
  int pid = fork();
  if(pid == 0){
    for(i=0 ; i < 100 ; ++i){
      int pid1 = fork();
      if(pid1 == 0){
        printf("第%d个僵尸进程\n",i+1);
        break;
      }
      else if(pid1 < 0){
        perror("创建进程失败\n");
        exit(1);
      }
    }
    while(1);
  }
  else if(pid < 0){
    perror("创建进程失败\n");
    exit(1);
  }
  return 0;
}

exec函数示例

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
int main(int argc,char *argv[])
{
    int pid1 = fork();
    if(pid1 == 0){
//  execlp("ls","ls","-l",NULL);
//  chdir(argv[1]);
//  execlp("ls","ls","-l",NULL);
        execlp("ls","ls","-l",argv[],NULL);
        return 20;
    }
    else if(pid1 > 0){
        int val = 0;
        if(wait(&val) == -1){
            printf("子进程回收失败\n");
            exit(-1);
        }
        if(WIFSIGNALED(val)){
            printf("进程异常终止\n");
        }
        else{
            printf("正常结束\n");
        }
        printf("子进程的返回值:%d\n",WEXITSTATUS(val));
        printf("val:%#o\n",val);
    }
    else{
        perror("创建进程失败\n");
        exit(-1);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值