进程的相关部分知识汇总

进程

进程和程序
  • 程序:死的,不占用系统资源(内存)
  • 进程:活跃的程序
  • 程序1:N进程
cpu
pcb进程控制块
  • 本质:结构体:struct task_struct{…} — find/usr/src/ -name
  • 存储目录位置: /usr/src/linux-headers…/sched.h
  • 大致存储内容
    • 进程状态
    • id
    • 当前工作目录
    • 虚拟地址空间映射信息
    • umask掩码
    • 用户id,组id
    • 文件描述符表
进程状态
  • 就绪态:完成准备,等待cpu划分时间片

  • 运行态:获取cpu时间片,正则运算

  • 挂起态:等待cpu以外其他资源。

  • 停止: 正常异常终止程序

  • 使用env查看系统环境变量

  • 环境变量语法格式: 名 = 值: 值: 值:

  • echo$ 环境变量名 查看对应值。如 echo $PATH

fork函数
pid_t fork(void);
成功:
    // fork之后,产生一个子进程。
    父进程:返回子进程id
    子进程:返回0
失败:
    

例子:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<fcntl.h>
#include<errno.h>
#include<dirent.h>
void sys_err(const char*str)
{
    perror(str);
    exit(1);
}

int main(int argc,char* argv[])
{
    printf("-------before fork----------\n");

    pid_t pid = fork();
    if(pid==-1)
        sys_err("fork err");
    if(pid==0) //子进程
    {
        printf("i'm a child 我的id  = %d 父进程 = %d\n",getpid(),getppid());
    }
    else if(pid >0)
    {
        printf("父进程,我儿子id  = %d,我的ID = %d  父父进程 = %d\n",pid,getpid(),getppid());
        sleep(1);
    }

    printf("-------after fork----------\n");


    return 0;
}
进程控制
  • fork之后,父子进程共同争cpu

  • ps|aux | grep 关键字 – 搜索关键字的进程

  • ./a.out 进程的父进程bash

  • 系统调用、库函数区别:

    • 系统调用:1、访问内核数据结构2、访问硬件资源
    • 库函数
循环创建n个子进程
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<fcntl.h>
#include<errno.h>
#include<dirent.h>
void sys_err(const char*str)
{
    perror(str);
    exit(1);
}

int main(int argc,char*argv[])
{
    int i = 0;
    for(i = 0;i<5;i++)
    {
        if(fork()==0)
            break;      //循环期间,子进程不参与
        
    }
    if(5 == i)
    {
        sleep(5);
        printf("i'm a parent\n");
    }
    else
    {
        sleep(i);
         printf("I'm %dth child\n",i+1);
    }
   
    return 0;
}
fork后父子进程异同

父子相同:

  • 全局变量、.data、.text

父子不同:

  • ​ 进程id,fork返回值、进程运行时间、父进程id、定时器
读时共享,写时复制
  • fork后,对于父进程的用户空间的数据,系统采用读时共享,写时复制
gdb调式父子进程
  • 在fork函数调用之前:
  • 跟踪父进程执行逻辑:set follow-fork-mode parent
  • 子进程: set follow-fork-mode child
exec函数族
  • 将当前进程的.text .data替换为索要加载程序的 .text .data。然后让进程从新的.text第一条指令开始执行。

  • exec函数族,一旦调用成功不会返回。失败才会,错误值为-1.errno。

execlp
  • p:path。自动借助环境变量path找寻可执行程序。

     #include <unistd.h>
    
    extern char **environ;
    
    int execl(const char *pathname, const char *arg, ...
                   /* (char  *) NULL */);
    

实例:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<fcntl.h>
#include<errno.h>
#include<dirent.h>
void sys_err(const char*str)
{
    perror(str);
    exit(1);
}

int main(int argc,char* argv[])
{
    pid_t pid = fork();
    if(pid == 0)
    {
        execlp("ls","ls","-l","-F","-a",NULL);
        perror("/bin/ls exec error");
        exit(1);
    }
    else if(pid > 0)
    {
        sleep(1);
        perror("parent\n");
    }
    return 0;
}
execl
#include <unistd.h>

extern char **environ;

int execl(const char *pathname, const char *arg, ...
               /* (char  *) NULL */);

直接指定药加载的程序绝对访问路径。可以是系统可以是执行文件,也可以是用户自定义的可执行文件

实例

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<fcntl.h>
#include<errno.h>
#include<dirent.h>
void sys_err(const char*str)
{
    perror(str);
    exit(1);
}

int main(int argc,char* argv[])
{
    pid_t pid = fork();
    if(pid == 0)
    {

        // execl("/bin/ls","ls","-l","-F","-a",NULL);
        execl("./while","while","Aa","bb","cc",NULL);
        perror("/bin/ls exec error");
        exit(1);
    }
    else if(pid > 0)
    {
        sleep(1);
        perror("parent\n");
    }
    return 0;
}
练习
  • 编写程序,创建子进程,子进程使用exec函数,获取当前系统中的进程详细信息,打印到一个文件中。

  • ps aux > out

  • #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include<unistd.h>
    #include<fcntl.h>
    #include<errno.h>
    #include<dirent.h>
    void sys_err(const char*str)
    {
        perror(str);
        exit(1);
    }
    
    int main(int argc,char * argv[])
    {
        pid_t pid = fork();
        if(pid == 0)
        {
            int fd = open("out",O_WRONLY|O_CREAT|O_TRUNC,0644);
            if(fd == -1)
            {
                sys_err("open err");
            }
            dup2(fd,STDOUT_FILENO);
            execlp("ps","ps","a","u","x",NULL);
            perror("execlp error");
            exit(1);
        }
        else if (pid > 0)
        {
            sleep(1);
            printf("I'm a parent\n");
        }
        return 0;
    }
    
进程回收
  • fork后的子进程,其父进程有义务在子进程结束时,回收该子进程。隔辈进程无回收关系。
  • 进程终止:
    1. 关闭所有文件描述符
    2. 释放用户空间分配的内存
    3. 进程的pcb残留在内核。保存进程结束的状态。
孤儿进程

父进程先于子进程终止。子进程沦为孤儿进程。

使用命令:ps ajx查看 ppid(父进程id) pid(进程id)

僵尸进程

子进程终止。父进程没有终止,没有对子进程回收。在此期间,子进程为僵尸进程。

杀死进程:kill -9 进程id

wait回收
#include <sys/types.h>
#include <sys/wait.h>

pid_t wait(int *wstatus);
// 传出参数.回收进程的状态
pid_t waitpid(pid_t pid, int *wstatus, int options);
返回值:
    成功,回收的进程pid
    失败 -1,errno
  • 函数的作用
    1. 阻塞等待子进程退出
    2. 回收子进程残留在内核的pcb
    3. 获取子进程的退出状态(正常,异常)
  • 回收子进程退出状态:
    • 正常退出
    • 异常退出
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<fcntl.h>
#include<errno.h>
#include<dirent.h>
void sys_err(const char*str)
{
    perror(str);
    exit(1);
}
int main(int argc,char*argv[])
{
    int status = 0;
    pid_t wpid = 0;
    pid_t pid = fork();
    if(pid == -1)
    {
        sys_err("fork err");
    }
    else if(pid == 0)
    {
        printf("I'm a child  pid = %d\n",getpid());
        int a = 5/0;
        sleep(1);
        exit(73);
    }
    else
    {
        wpid = wait(&status);
    }
    if(wpid==-1)
    {
        sys_err("wait err");
    }
    if(WIFEXITED(status))
    {
        printf("I'm a parent,pid = %d child, exit code = %d\n",wpid,WEXITSTATUS(status));
    }
    else if(WIFSIGNALED(status))
    {
        //宏函数为真,说明子进程被信号终止
        printf("I''m a parent, pid = %d child, killed by %d signal\n",wpid,WTERMSIG(status));
    }
    return 0;
}
waitpid回收
#include <sys/types.h>
#include <sys/wait.h>pid_t waitpid(pid_t pid, int *status, int options);
功能:
    等待子进程终止,如果子进程终止了,此函数会回收子进程的资源。
​
参数:
    pid : 参数 pid 的值有以下几种类型:
      pid > 0  等待进程 ID 等于 pid 的子进程。
      pid = 0  等待同一个进程组中的任何子进程,如果子进程已经加入了别的进程组,waitpid 不会等待它。
      pid = -1 等待任一子进程,此时 waitpid 和 wait 作用一样。
      pid < -1 等待指定进程组中的任何子进程,这个进程组的 ID 等于 pid 的绝对值。
​
    status : 进程退出时的状态信息。和 wait() 用法一样。
​
    options : options 提供了一些额外的选项来控制 waitpid()0:同 wait(),阻塞父进程,等待子进程退出。
            WNOHANG:没有任何已经结束的子进程,则立即返回。
            WUNTRACED:如果子进程暂停了则此函数马上返回,并且不予以理会子进程的结束状态。(由于涉及到一些跟踪调试方面的知识,加之极少用到)
                 
返回值:
    waitpid() 的返回值比 wait() 稍微复杂一些,一共有 3 种情况:
        1) 当正常返回的时候,waitpid() 返回收集到的已经回收子进程的进程号;
        2) 如果设置了选项 WNOHANG,而调用中 waitpid() 发现没有已退出的子进程可等待,则返回 03) 如果调用中出错,则返回-1,这时 errno 会被设置成相应的值以指示错误所在,如:当 pid 所对应的子进程不存在,或此进程存在,但不是调用进程的子进程,waitpid() 就会出错返回,这时 errno 被设置为 ECHILD;
  • 26
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值