Linux 进程

你的名字 2022-06-15 06:26 347阅读 0赞
  • 进程

    • 常用的函数

      • atexit
      • 进程资源限制getrlimit
      • 进程标识getpid
      • 进程创建fork
      • wait函数
      • exec函数
      • system 函数
    • 常用函数代码示例

      • 环境表
      • fork函数代码示例

        • 子父进程区别与wait函数测试
        • 孤儿进程和僵尸进程示例
      • exec函数示例

进程

  • 有代码的就是程序,正在跑的程序就是进程。
  • 几个重要的linux 查看进程的命令需要记忆!
  1. * Ps命令, Pprogcess(进程的意思),sstatus(状态的意思),ps 就是查看进程状态。
  2. * Ps ef
  3. * Ps aux
  4. * ps ax 0 pid ppid
  5. * ps-ef | grep 关键字

常用的函数

atexit()

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























内核 return exit() _exit() / _Exit()
I/O缓存 Y Y N
调用终止函数 Y Y N

进程资源限制getrlimit()

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

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

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

  • resource取值
  1. * RLIMIT\_AS 进程可用存储区大小
  2. * RLIMIT\_CORE core文件最大字节数
  3. * RLIMIT\_CPU CPU时间最大值
  4. * RLIMIT\_DATA 数据段最大长度
  5. * RLIMIT\_FSIZE 可创建文件的最大长度
  6. * RLIMIT\_LOCKS 文件锁的最大数
  7. * RLIMIT\_MEMLOCK 使用mlock能否在存储器中锁定的最长字节数
  8. * RLIMIT\_NOFILE 能打开的最大文件数
  9. * RLIMIT\_NPROC 每个用户ID可拥有的最大子进程数.
  10. * RLIMIT\_RSS 最大驻内存集的字节长度
  11. * 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。
  • 创建子进程,父子进程哪个先运行根据系统调度且复制父进程的内存空间。
  1. * 子进程的继承属性:用户信息和权限、目录信息、信号信息、环境、共享存储段、资源
  2. 限制、堆、栈和数据段,共享代码段。
  3. * 子进程特有属性:进程ID、锁信息、运行时间、未决信号
  4. * 子进程只继承父进程的文件描述表,不继承但共享文件表项和i-node
  • vfork创建子进程,但子进程先运行且不复制父进程的内存空间。

  • pid_t fork(void);

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

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

wait函数

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

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

  • status参数:为空时,代表任意状态结束的子进程,若不为空,则代表指定状态结束的子进程。
  • wait和waitpid函数区别
  1. * 在一个子进程终止前,wait使其调用者阻塞
  2. * waitpid有一选择项,可使调用者不阻塞。
  3. * waitpid等待一个指定的子进程,而wait等待所有的子进程,返回任一终止子进程的状态。
  • 检查wait和waitpid函数返回终止状态的宏
  1. * WIFEXITED/WEXITSTATUS(status):若为正常终止子进程返回的状态,则为真。
  2. * WIFSIGNALED/WTERMSIG(status):若为异常终止子进程返回的状态,则为真(接到一个不能捕捉的信号)
  3. * WIFSTOPED/WSTOPSIG(status):若为当前暂停子进程的返回的状态,则为真。
  • options参数
  1. * WNOHANG:若由pid指定的子进程没有退出则立即返回,则waitpid不阻塞此时其返回值为0
  2. * WUNTRACED:若某实现支持作业控制,则由pid指定的任一子 进程状态已暂停,且其状态自暂停以来还未报告过,则返回其状态。
  • waitpid函数的pid参数
  1. * pid == -1 :等待任一子进程,功能与wait等效。
  2. * pid > 0 :等待其进程IDpid相等的子进程
  3. * pid == 0 :等待其组ID等于调用进程的组ID的任一子进程
  4. * 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. * 返回:出错返回-1,成功则不返回
  • exec系列函数的注意点
  1. * execve函数为系统调用,其余为库函数。执行execve函数后面的代码不执行。
  2. * execlpexecvp函数中的pathame,相对和绝对路径均可使用,其它四个函数中的 pathname只能使用绝对路径。相对路径一定要在进程环境表对应的PATH中。
  3. * argv参数为新程序执行main函数中传递的argv参数,最后一个元素为NULL
  4. * envp为进程的环境表

system 函数

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

常用函数代码示例

环境表

  • extern char **environ
  1. * 每个进程都有一个独立的环境表
  2. * 初始的环境表继承自父进程
  • 获得环境表信息案例

    include

    include

    include

    extern char *environ;
    int main(int argc, char
    argv[]){
    int i = 0;
    char *ptr = environ[i];
    while(ptr != NULL){

    1. printf("%s\n", ptr);
    2. ptr = environ[++i];

    }
    return 0;
    }

  • 环境变量操作函数

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

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

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

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

fork函数代码示例

子父进程区别与wait()函数测试

  1. #include <stdio.h>
  2. #include <sys/types.h>
  3. #include <unistd.h>
  4. #include <stdlib.h>
  5. #include <sys/wait.h>
  6. int main(void)
  7. {
  8. printf("%d\n",getpid());
  9. int a = 0,i = 0;
  10. int pid1 = fork();
  11. if(pid1 == 0){
  12. a=10;
  13. for(i=0 ; i < 3 ; ++i){
  14. printf("我是子进程:%d\n",getpid());
  15. sleep(1);
  16. }
  17. // while(1);
  18. return 20;
  19. }
  20. else if(pid1 > 0){
  21. printf("a:%d",a);
  22. int val = 0;
  23. for(i=0 ; i < 5 ; ++i){
  24. printf("我是父进程:%d\n",getpid());
  25. sleep(1);
  26. }
  27. if(wait(&val) == -1){
  28. printf("子进程回收失败\n");
  29. exit(-1);
  30. }
  31. if(WIFSIGNALED(val)){
  32. printf("进程异常终止\n");
  33. }
  34. else{
  35. printf("正常结束\n");
  36. }
  37. printf("子进程的返回值:%d\n",WEXITSTATUS(val));
  38. printf("val:%#o\n",val);
  39. }
  40. else{
  41. perror("创建进程失败\n");
  42. exit(-1);
  43. }
  44. return 0;
  45. }

孤儿进程和僵尸进程示例

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <sys/types.h>
  4. #include <sys/wait.h>
  5. #include <unistd.h>
  6. #include <string.h>
  7. int main(void)
  8. {
  9. int i = 0;
  10. int pid = fork();
  11. if(pid == 0){
  12. for(i=0 ; i < 100 ; ++i){
  13. int pid1 = fork();
  14. if(pid1 == 0){
  15. printf("第%d个僵尸进程\n",i+1);
  16. break;
  17. }
  18. else if(pid1 < 0){
  19. perror("创建进程失败\n");
  20. exit(1);
  21. }
  22. }
  23. while(1);
  24. }
  25. else if(pid < 0){
  26. perror("创建进程失败\n");
  27. exit(1);
  28. }
  29. return 0;
  30. }

exec函数示例

  1. #include <stdio.h>
  2. #include <sys/types.h>
  3. #include <unistd.h>
  4. #include <stdlib.h>
  5. #include <sys/wait.h>
  6. int main(int argc,char *argv[])
  7. {
  8. int pid1 = fork();
  9. if(pid1 == 0){
  10. // execlp("ls","ls","-l",NULL);
  11. // chdir(argv[1]);
  12. // execlp("ls","ls","-l",NULL);
  13. execlp("ls","ls","-l",argv[],NULL);
  14. return 20;
  15. }
  16. else if(pid1 > 0){
  17. int val = 0;
  18. if(wait(&val) == -1){
  19. printf("子进程回收失败\n");
  20. exit(-1);
  21. }
  22. if(WIFSIGNALED(val)){
  23. printf("进程异常终止\n");
  24. }
  25. else{
  26. printf("正常结束\n");
  27. }
  28. printf("子进程的返回值:%d\n",WEXITSTATUS(val));
  29. printf("val:%#o\n",val);
  30. }
  31. else{
  32. perror("创建进程失败\n");
  33. exit(-1);
  34. }
  35. return 0;
  36. }

发表评论

表情:
评论列表 (有 0 条评论,347人围观)

还没有评论,来说两句吧...

相关阅读

    相关 Linux进程

    当当当当~~,你是不是好奇什么是进程呢?这篇文章带你了解了解什么是进程,及其进程相关知识。 1. 什么是进程 从操作系统角度分析,进程是一个运行中程序描述 ——

    相关 Linux 进程

    目录 操作系统 进程 进程概念 进程的描述--PCB task\_ struct内容分类 进程的组织 查看进程 通过系统调用接口获取进程标志符(进程ID) 进

    相关 Linux 进程

    一 进程基本概念 1.1 进程和程序 进程(process):是一个可执行程序(program)的实例。更精确的定义是:进程是允许某个并发执行的程序在某个数据集合上

    相关 Linux进程

    一、什么是进程 Unix标准定义:一个其中运行着一个或多个线程的地址空间和这些线程所需要的系统资源。 进程由 程序代码、数据、打开文件描述符、栈空间、环境空间等组成。

    相关 linux 进程

    进程:运行中的程序(打开的文件,挂起的信号,内存,执行线程等等) 线程(pc,寄存器(线程需记录cpu寄存器的值,以挂起后恢复执行),栈),调度对象,在liux里是特殊进程

    相关 linux进程

    一、概念 Linux 是一种动态系统,能够适应不断变化的计算需求。linux 计算需求的表现是以进程的通用抽象为中心的。进程可以是短期的(从命令行执行的一个命令),也可以是

    相关 linux-进程

    程序与进程 程序:通常为binary program,放置在存储媒体中,为实体文件的形态存在 进程:程序被触发后,执行者的权限和属性,程序的程序代码与所需