Linux 进程

来源:互联网 发布:淘宝网c2c商业模式 编辑:程序博客网 时间:2024/05/17 02:51

  • 进程
    • 常用的函数
      • atexit
      • 进程资源限制getrlimit
      • 进程标识getpid
      • 进程创建fork
      • wait函数
      • exec函数
      • system 函数
    • 常用函数代码示例
      • 环境表
      • fork函数代码示例
        • 子父进程区别与wait函数测试
        • 孤儿进程和僵尸进程示例
      • exec函数示例

进程

  • 有代码的就是程序,正在跑的程序就是进程。
  • 几个重要的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
    • 每个启动的进程都默认登记了一个标准的终止函数
    • 终止函数在进程终止时释放进程所占用的一些资源
    • 登记的多个终止函数执行顺序是以栈的方式执行,先登记的后执行。
内核 return exit() _exit() / _Exit() I/O缓存 Y Y N 调用终止函数 Y Y N

进程资源限制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;}
原创粉丝点击