zoukankan      html  css  js  c++  java
  • 进程笔记

    学习笔记(二)之进程:

    进程:本质是程序一次动态执行的过程 动态的 有生命周期 不能保存(临时存放于RAM上)

    程序:本质是由源码编译生成的二进制可执行文件(指令和数据的集合) 静态的 无生命周期
    可以报存(ROM)

    注:即使是同一个程序多次执行产生进程也是不同的进程!!!

    进程动态执行的一次过程:
    1.创建 fork exec
    2.调度
    分时:将CPU的工作时间进行等均切割,进行合理分配,实现宏观上并行,微观上串行

    进程基本三态: 就绪态 运行态 阻塞态

    进程管理命令:
    1.ps 进程信息截屏
    ps -ef
    ps aux

    UID:用户编号
    PID:进程编号 init 1 始祖进程
    PPID:父进程编号
    STAT:进程状态
    R:运行态
    T:暂停态
    S:阻塞态
    Z:僵尸态

    <:进程优先级较高
    N:进程优先级较低
    s:进程的领导者
    l:多线程
    +:在前台运行
    2.kill命令:给指定进程发送信号
    kill -信号编号 PID
    kill -l:列出信号 SIGINT 2 ctrl+c
    SIGSTOP 19 ctrl+z
    SIGKILL 9

      top 类似windows 任务管理器 q退出界面
      pstree 以树状图形式显示所有进程

    3.执行 CPU执行
    4.消亡 exit _exit

    进程三要素:
    1.程序 指令代码
    2.内存分段
    3.进程控制块 PCB task_struct 结构体 用于记录进程信息(PID,STAT,指向父进程的指针,记录所有子进程的列表)

    getpid:获取调用进程的PID
    pid_t getpid(void);

    getppid:获取调用进程父进程的PID
    pid_t getppid(void);

     1 #include<stdio.h>
     2 #include <sys/types.h>
     3 #include <unistd.h>
     4 
     5 
     6 
     7 int main(int argc, const char *argv[])
     8 {
     9     pid_t pid,ppid;
    10     pid = getpid();
    11     ppid = getppid();
    12 
    13     printf("%d %d\n",pid,ppid);
    14     while(1)
    15     {
    16         ;
    17     }
    18 
    19     return 0;
    20 }
    getppid

    进程创建:fork
    pid_t fork(void);
    功能:将当前调用进程进行精确的拷贝产生一个新的进程,新的进程称为子进程,调用进程称为父进程
    返回值:失败在父进程中返回-1,并设置errno号,子进程不会被创建
    成功时,在父进程中看到的返回值是子进程的pid,在子进程中看到的返回值是0

     1 #include <stdio.h>
     2 #include <unistd.h>
     3 #include <sys/types.h>
     4 #include <stdlib.h>
     5 #include <sys/wait.h>
     6 
     7 
     8 
     9 int main(int argc, const char *argv[])
    10 {
    11     pid_t pid;
    12     pid_t pid_ret;
    13 
    14 
    15     pid = fork();  //该语句后子进程出现
    16     if(pid < 0)   //创建子进程失败
    17     {
    18         perror("fail to fork");
    19         exit(1);
    20     }
    21     else if(pid == 0) //子进程看到的代码块
    22     {
    23         printf("pid:%d child_pid:%d ppid:%d\n",pid,getpid(),getppid());
    24         sleep(5);
    25         exit(0);
    26     }
    27     else  // pid>0  父进程看到的代码块,得到的返回值是子进程的pid
    28     {
    29         printf("child_pid:%d pid:%d\n",pid,getpid());
    30     //    pid_ret = wait(NULL);//阻塞等待子进程退出
    31         
    32     //    pid_ret = waitpid(-1,NULL,0);waitpid阻塞
    33 
    34     //    pid_ret = waitpid(-1,NULL,WNOHANG);waitpid非阻塞
    35         printf("pid_ret:%d\n",pid_ret);
    36         exit(0);
    37     }
    38 
    39     return 0;
    40 }
    fork

    进程退出:exit man 3 _exit man 2
    exit
    void exit(int status);
    功能:退出当前进程,刷新和关闭所有打开的文件流,并返回退出状态给当前进程的父进程 status & 0377
    参数:退出状态可以自定义 官方提供的宏可以直接使用 EXIT_SUCCESS 0 EXIT_FAILURE 1

    _exit
    void _exit(int status);
    功能:立刻退出当前进程,关闭所有属于该进程的文件描述符,将所有的子进程交给init关系,给当前进程的父进程发送SIGCHLD
    的信号,并返回退出状态给父进程
    参数:退出状态可以自定义 官方提供的宏可以直接使用 EXIT_SUCCESS 0 EXIT_FAILURE 1

    wait
    pid_t wait(int *status);
    功能:1.用与父进程中阻塞等待任意子进程状态改变(1.子进程退出(使用exit) 2.被信号停止 3.被信号恢复),2.当子进程退出时父进程会使用wait"收尸"(回收子进程相关资源),回收不及时会造成僵尸进程!
    返回值:成功返回被回收的子进程的PID,失败返回-1
    参数:如果不关子进程的状态改变,则直接填NULL
    如果关心子进程状态改变,准备一个int型变量,取地址放入wait中,结合一下宏函数操作:
    宏函数:
    WIFEXITED(status) 判断子进程是否正常退出(使用exit _exit) 如果是返回true
    WIFSIGNALED(status) 判断子进程是否被信号中断 如果是则返回true
    WEXITSTATUS(status) 使用时必须保证该子进程退出时使用的时exit或者_exit退出
    解析子进程使用exit函数返回status中的信息

     1 #include <stdio.h>
     2 #include <unistd.h>
     3 #include <sys/types.h>
     4 #include <stdlib.h>
     5 #include <sys/wait.h>
     6 
     7 
     8 
     9 int main(int argc, const char *argv[])
    10 {
    11     pid_t pid;
    12 
    13 
    14     pid = fork();  //该语句后子进程出现
    15     if(pid < 0)   //创建子进程失败
    16     {
    17         perror("fail to fork");
    18         exit(1);
    19     }
    20     else if(pid == 0) //子进程看到的代码块
    21     {
    22         printf("pid:%d child_pid:%d ppid:%d\n",pid,getpid(),getppid());
    23         sleep(10);
    24         exit(2);
    25     }
    26     else  // pid>0  父进程看到的代码块,得到的返回值是子进程的pid
    27     {
    28         printf("child_pid:%d pid:%d\n",pid,getpid());
    29         int s;
    30         wait(&s);//阻塞等待子进程退出
    31         if(WIFEXITED(s))
    32         {
    33             printf("child is exit!\n");
    34             printf("exit_status:%d\n",WEXITSTATUS(s));
    35         }
    36         else if(WIFSIGNALED(s))
    37         {
    38             printf("child is killed by signal!\n");
    39         }
    40 
    41         exit(0);
    42     }
    43 
    44     return 0;
    45 }
    wait

    waitpid:
    pid_t waitpid(pid_t pid, int *status, int options);
    参数:
    1.pid:
    -1:代表等待任意子进程状态发生改变
    >0:(子进程pid编号)等待指定的子进程状态发生改变
    0:代表等待与当前进程同一组内的所有子进程的状态发生改变
    2.同wait一致
    3.选项 0 默认阻塞(与wait一致) WNOHANG 默认非阻塞
    返回值:成功返回回收子进程的pid号,失败返回-1,如果选项使用的是WNOHANG,则没有子进程退出时返回0
    waitpid(-1,&status,0) == wait(&status)

    僵尸进程:僵尸进程是问题,要解决 详见:man 2 wait NOTES
    孤儿进程:不是问题,当父进程退出,子进程还没有结束,所有的子进程就变成孤儿进程,交给init管理
    init能一瞬间回收所有退出的子进程
    1.wait waitpid 无法同时回收多个退出的子进程,有效率问题

    2.信号注册 SIGCHLD
    signal
    sighandler_t signal(int signum, sighandler_t handler);
    功能:向内核注册指定信号,当当前进程收到该对应信号时,执行指定操作
    参数:1.需要被注册的信号 2.指定操作
    signal(SIGCHLD,SIG_IGN); 信号忽略操作

     1 #include <stdio.h>
     2 #include <unistd.h>
     3 #include <sys/types.h>
     4 #include <stdlib.h>
     5 #include <sys/wait.h>
     6 #include <signal.h>
     7 
     8 
     9 
    10 int main(int argc, const char *argv[])
    11 {
    12     signal(SIGCHLD,SIG_IGN); 
    13     //向内核注册SIGCHLD,当该进程收到这个信号时,选择忽略 
    14 
    15     pid_t pid;
    16     pid_t pid_ret;
    17 
    18 
    19     pid = fork();  //该语句后子进程出现
    20     if(pid < 0)   //创建子进程失败
    21     {
    22         perror("fail to fork");
    23         exit(1);
    24     }
    25     else if(pid == 0) //子进程看到的代码块
    26     {
    27         printf("pid:%d child_pid:%d ppid:%d\n",pid,getpid(),getppid());
    28         exit(0);
    29     }
    30     else  // pid>0  父进程看到的代码块,得到的返回值是子进程的pid
    31     {
    32         sleep(3);
    33         pid_ret = waitpid(-1,NULL,WNOHANG);//waitpid非阻塞
    34         printf("pid_ret:%d\n",pid_ret);
    35         exit(0);
    36     }
    37 
    38     return 0;
    39 }
    signal

    3.父子孙
    父创建子 子立马创建孙 子自杀 父进程回收子,父做自己的事 孙交给init,孙进程做自己的事

     1 #include <stdio.h>
     2 #include <unistd.h>
     3 #include <stdlib.h>
     4 #include <sys/types.h>
     5 
     6 
     7 int main(int argc, const char *argv[])
     8 {
     9     pid_t pid1,pid2;
    10 
    11 
    12     pid1 = fork();  //父创建子进程
    13     if(pid1 < 0)
    14     {
    15         perror("fail to fork1");
    16         exit(1);
    17     }
    18     else if(pid1 == 0) //子进程
    19     {
    20         pid2 = fork(); //子创建孙
    21         if(pid2 < 0)
    22         {
    23             perror("fail to fork2");
    24             exit(1);
    25         }
    26         else if(pid2 == 0)//孙进程
    27         {
    28             sleep(5);
    29             printf("父亲被残忍杀害,爷爷不管,交给孤儿院!\n");
    30             printf("getppid:%d\n",getppid());
    31             exit(0);
    32         }
    33         else  //子进程
    34         {
    35             printf("惨无人道被杀害的子进程,心态爆炸!\n");
    36             exit(0);
    37         }
    38     }
    39     else  //父进程
    40     {
    41         wait(NULL); 
    42         //回收自杀的子进程,由于子进程创建孙进程很快,不做任何事就退出,父进程等待回收时基本不会受到影响
    43         printf("嘿嘿嘿!\n");
    44         exit(0);
    45     }
    46 
    47     return 0;
    48 }
    父子孙

    exec函数族: 将指定的新的可执行文件替换当前进程的0~3G空间
    l:list(以列表形式排布) p:path(通过shell查找) e:env 环境 v: vector
    execl:
    int execl(const char *path, const char *arg, ...);
    参数:1.新的可执行文件的路径 2.命令行传参,以列表形式排布,以NULL结尾 3. ...代表可变长度传参

     1 #include <stdio.h>
     2 #include <unistd.h>
     3 
     4 
     5 
     6 int main(int argc, const char *argv[])
     7 {
     8     printf("before execl!\n");
     9 
    10     execl("/home/xyx/teach/18072/Pro_2/hello","./hello",NULL);
    11 
    12     printf("after execl!\n");
    13 
    14     return 0;
    15 }
    execl

    execlp:
    int execlp(const char *file, const char *arg, ...);
    参数:1.新的可执行文件名(自动查找路径) 2.命令行传参,以列表形式排布,以NULL结尾 3. ...代表可变长度传参

     1 #include <stdio.h>
     2 #include <unistd.h>
     3 
     4 
     5 
     6 int main(int argc, const char *argv[])
     7 {
     8     printf("before execlp!\n");
     9     
    10     execlp("ls","ls","-l",NULL);
    11 
    12     printf("after execlp!\n");
    13     
    14     return 0;
    15 }
    eleclp

    execv:
    int execv(const char *path, char *const argv[]);
    参数:1.新的可执行文件路径 2.命令行传承,以数组方式填写(自己准备数组,最后一个元素依旧是NULL)

     1 #include <stdio.h>
     2 #include <unistd.h>
     3 
     4 
     5 
     6 int main(int argc, const char *argv[])
     7 {
     8     printf("before execv!\n");
     9     char * a[] = {"./hello",NULL};
    10     execv("/home/xyx/teach/18072/Pro_2/hello",a);
    11     printf("after execv!\n");
    12     return 0;
    13 }
    execv

    execle:
    int execle(const char *path, const char *arg, ..., char * const envp[]);
    参数:1.新的可执行文件的路径 2.命令行传参,以列表形式排布,以NULL结尾 3. ...代表可变长度传参 4.自己提供的环境变量

     1 #include <stdio.h>
     2 #include <unistd.h>
     3 
     4 
     5 
     6 int main(int argc, const char *argv[])
     7 {
     8     printf("before execle!\n");
     9     char * env[] = {"PATH=hehe","LOGANNAME=heihei",NULL};
    10     execle("/usr/bin/env","env",NULL,env);
    11     printf("after execle!\n");
    12     return 0;
    13 }
    execle

    终端上执行a.out:
    bash --> fork --> exec(a.out)

    system:跳出进程执行shell命令,执行完成后返回当前调用进程
    int system(const char *command);
    参数:shell命令

     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 
     4 
     5 
     6 int main(int argc, const char *argv[])
     7 {
     8     printf("before system!\n");
     9     system("ls -l");
    10     printf("after system!\n");
    11     return 0;
    12 }
    system

    交互进程:与终端产生交互
    前台进程(输入输出都存在): 后台运行过程中输入fg切换为前台运行
    后台进程(只有输出): 后台运行a.out: (1) ./a.out & (2)ctrl+z暂停进程 用bg回复进程到后台运行

    守护进程:与终端无关 ,从开始运行,一直到主动杀死或者操作系统结束才会终止
    1.创建子进程,父进程退出,子进程交给init接管
    2.设置当前进程为会话组组长
    setsid:
    pid_t setsid(void);
    3.改变了工作路径
    chdir
    int chdir(const char *path);
    4.更改文件权限掩码
    umask(0)
    mode_t umask(mode_t mask);
    5.关闭文件描述符
    getdtablesize: 返回当前进程能打开的最大的文件个数 1024
    int getdtablesize(void);
    利用for结合close循环关闭文件描述符

    注:有输出时需要依靠fflush函数实现

     1 #include <stdio.h>
     2 #include <unistd.h>
     3 #include <stdlib.h>
     4 #include <sys/types.h>
     5 #include <sys/stat.h>
     6 
     7 
     8 int main(int argc, const char *argv[])
     9 {
    10     pid_t  pid;
    11 
    12 
    13     pid = fork();
    14     if(pid < 0)
    15     {
    16 
    17     }
    18     else if(pid == 0)
    19     {
    20         //设置会话组组长
    21         setsid();
    22 
    23         //更改工作路径
    24         chdir("/home/xyx");
    25 
    26         //更改文件权限掩码
    27         umask(0);
    28 
    29 
    30         //关闭所有打开的文件描述符
    31         int size_fd;
    32         size_fd = getdtablesize();
    33         int i;
    34         for(i = 0;i < size_fd;i++)
    35         {
    36             close(i);
    37         }
    38         printf("11111\n");        
    39         sleep(50);
    40     }
    41     else
    42     {
    43         exit(0);
    44     }
    45 
    46 
    47 
    48     return 0;
    49 }
    守护进程
     1 #include <stdio.h>
     2 #include <unistd.h>
     3 #include <stdlib.h>
     4 #include <sys/types.h>
     5 #include <sys/stat.h>
     6 #include <time.h>
     7 
     8 
     9 int main(int argc, const char *argv[])
    10 {
    11     pid_t  pid;
    12 
    13 
    14     pid = fork();
    15     if(pid < 0)
    16     {
    17 
    18     }
    19     else if(pid == 0)
    20     {
    21         //设置会话组组长
    22         setsid();
    23 
    24         //更改工作路径
    25         chdir("/home/xyx");
    26 
    27         //更改文件权限掩码
    28         umask(0);
    29 
    30 
    31         //关闭所有打开的文件描述符
    32         int size_fd;
    33         size_fd = getdtablesize();
    34         int i;
    35         for(i = 0;i < size_fd;i++)
    36         {
    37             close(i);
    38         }
    39 
    40         FILE *fp;
    41         fp = fopen("/home/xyx/log.txt","a");
    42         if(fp == NULL)
    43         {
    44             perror("fail to fopen");
    45             exit(1);
    46         }
    47     
    48         time_t t;
    49 
    50         while(1)
    51         {
    52             t = time(NULL);
    53             fprintf(fp,"%s\n",ctime(&t));
    54             fflush(fp);
    55             sleep(1);
    56         }
    57     }
    58     else
    59     {
    60         exit(0);
    61     }
    62 
    63 
    64 
    65     return 0;
    66 }
    daemon_time
  • 相关阅读:
    FICO-错误日志集
    FICO-财务凭证验证及替代
    FICO-Payment Terms 收付款条件和分期付款设置
    ABAP-JCO服务端连接问题
    LES-整车企业物料拉动系统的设计和实现
    工程数学-微积分
    web前端(15)—— JavaScript的数据类型,语法规范2
    web前端(14)—— JavaScript的数据类型,语法规范1
    web前端(13)—— 了解JavaScript,JavaScript的引入方式
    web前端(12)—— 页面布局2
  • 原文地址:https://www.cnblogs.com/hslixiqian/p/9559309.html
Copyright © 2011-2022 走看看