栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 系统运维 > 运维 > Linux

linux -- 初识进程

Linux 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

linux -- 初识进程

目录
    • 一、进程创建
      • 1.1、创建进程
      • 1.2、获取进程号
      • 1.3、让子进程执行新任务
    • 二、进程退出和等待
      • 2.1、进程退出
      • 2.2、僵尸进程和进程等待

一、进程创建 1.1、创建进程
#include 
#include 

pid_t fork(void);
pid_t vfork(void);

两者执行成功返回大于等于0的值,失败返回 -1
返回大于0的值(子进程的pid)表示在父进程中
返回0表示在子进程中
并发异步执行

后面的函数若无说明,则头文件和fork()一样

  • fork()
    子进程会复制父进程的所有资源,采用写时复制
    父子进程内存空间相互独立
    父子进程执行顺序不确定,由cpu调度决定
    若父进程先结束,则子进程会成为孤儿进程,被init进程收养
  • vfork()
    子进程共享父进程的内存空间(全局变量,堆栈),并于父进程执行
    创建进程系统开销更小
    执行顺序固定容易发生死锁,
    共享内存空间容易造成进程间同步错误
1.2、获取进程号
pid_t getpid(void);
pid_t getppid(void);
  • getpid
    获取当前进程的进程号
    成功返回调用进程的进程号,失败返回 -1
  • getppid
    获取父进程的进程号
    成功返回父进程号,失败返回 -1

在linux中 父进程的父进程是shell ,可以通过以下命令查看shell的进程号

$ ps -aux | grep bash
1.3、让子进程执行新任务

由于子进程的代码是从父进程拷贝来的,所以一般情况下所做工作与父进程一样
可以用execve函数在进程中运行另一个程序

int execvp(const char *file, char *const argv[]);
  • 参数含义
    file: 待运行的程序名
    argv[] : 运行时的参数
    (可以有多个,以NULL结尾,第一个参数一般同file)

  • 返回值
    成功 无返回
    失败 -1

1.3.1 测试 execvp

  • 先写个hello程序

    #include 
    #include 
    int main(int argc,char* argv[]) {
        printf("n******************************n");
        if(argc < 2){
            printf("Too few parameters !n");
        }
        else if(argc == 2){
            printf("Program name = "%s"n",argv[0]);
            printf("The parameter is "%s"n",argv[1]);
            printf("pid = %d   ppid = %dn",getpid(),getppid());
        } else{
            printf("Too many parameters !n");
       }
        printf("******************************nn");
        return 0;
    }
    
    $ gcc -o hello hello.c
    
  • execvp程序

    #include 
    #include 
    int main() {
        pid_t pid;
        pid = fork();
        if(pid<0){
            perror("fork");
        }
        else if(pid == 0){
    		//子进程
            printf("nin child process,pid = %dn",getpid());
            char *file = "./hello";
            char *argv[] = {file,"hello word",NULL};
            printf("use execvpn");
            int ret = execvp(file,argv);
            printf("ret = %dn",ret);
        }
        else{
            //父进程
            sleep(1);
            printf("in parent process,pid = %dn",getpid());
        }
        return 0;
    }
    

    子进程先结束

    父进程先结束 (调整sleep函数)

  • 说明

    1、execvp调用并没有生成新进程
    2、一旦调用该函数,进程本身就结束了(子进程最后一段没有打印)
    3、调用该函数的进程只会保留进程ID,但对系统来说还是同一个进程
    4、exec类函数还有5个 他们都是调用 execve 这个系统调用来实现的
    5、在父进程结束后的子进程成为孤儿进程 会被init进程接收,init进程pid为 1

二、进程退出和等待 2.1、进程退出

2.1.1、_exit()

void _exit(int status);
  • status的值
    0: 正常退出,非0:异常退出
  • 函数功能
    1、关闭进程打开的所有文件描述符、目录描述符
    2、清除进程使用的内存空间
    3、将该进程的 ppid 设置为init 进程的pid
    4、向父进程发送SIGCHLD信号
    5、如果父进程调用wait或waitpid来等待子进程结束,则唤醒父进程,取得终止进程的status
    6、结束进程
  • 不会刷新IO缓存
    return 将控制权交给主调函数
    exit、_exit 将控制权交给系统

2.1.2、exit , on_exit

#include 

void exit(int status);
int on_exit(void (*function)(int , void *), void *arg);
  • exit
    用法和_exit类似 但处理机制不一样 _exit只是exit要调用函数中的一个
    会刷新IO缓存 (调用fflush)

  • on_exit
    注册一个进程正常终止前的处理函数 对_exit不生效
    返回值:成功 0,失败 非0
    function:表示要注册的函数 arg:表示要传入的指针,可以为NULL

  • 简单测试

    #include 
    #include 
    #include 
    
    char fun(int status, void *arg){
      printf("status = %d,arg = %sn",status,(char*)arg);
      return '0';
    }
    int main() {
      on_exit((void *)fun,(void *)"hello");
      on_exit((void *)fun,NULL);
    
      printf("on_exit testn");
      exit(123);
    }
    

  • 说明

    1、 如果注释掉exit(),status会等于 0
    2、将exit换为_exit on_exit会失败
    3、推测注册方式为压栈

2.2、僵尸进程和进程等待

2.2.1、僵尸进程

  • 含义
    子进程比父进程后终止:子进程为孤儿进程 ,这进程没马
    子进程比父进程先终止:子进程为僵尸进程

  • 查看

    使用以下命令查看僵尸进程 STAT 中 Z+表示僵尸进程

    $ ps -u | grep Z
    
  • 处理
    1、父进程调用wait或waitpid函数(调用会阻塞自己),回收
    2、父进程将信号处理函数设为SIG_IGN 让内核去处理子进程
    3、fork两次,结束一级子进程,令二级子进程成为孤儿进程,让init去清理(不好操作)

2.2.2、进程等待函数

#include 
#include 

pid_t wait(int *wstatus);
pid_t waitpid(pid_t pid, int *wstatus, int options);
  • 参数说明
    wstatus:用于存放子进程的终止状态, 可以为NULL
    pid:子进程的进程号 若为 -1 表示等待任 一 子进程
    options:包括 WNOHANG、WUNTRACED、WCONTINUED (waitpid)
  • 返回值
    大于0 :子进程的进程号
    等于0:不阻塞 (waitpid)
    -1 出错
  • 测试

    #include 
    #include 
    #include 
    #include 
    
    int main() {
        int status1 = -2;
        int status2 = -2;
        pid_t pid;
        pid = fork();
        if(pid<0){
            perror("fork");
        }
        else if(pid == 0){
        	//子进程 1
            printf("in child1 process : pid = %d  ppid = %dn",getpid(),getppid());
            _exit(0);//正常退出
        }
        else
        {
        	//父进程
           pid =  fork();
            if(pid<0){
                perror("fork");
            } else if(pid == 0){
            	//子进程 2
                printf("in child2 process : pid = %d  ppid = %dn",getpid(),getppid());
                _exit(-1);//错误退出
            }
            else{
                //父进程
                printf("in parent process,pid = %dn",getpid());
    
                printf("cpid = %d t", wait(&status1));
                printf("status1 = %dn", status1);
                sleep(1);//让子进程先结束
                
                printf("cpid = %d t",wait(&status2));
                //printf("cpid = %d t",waitpid(-1,&status2,0));
                printf("status2 = %dn",status2);
            }
        }
        return 0;
    }
    
    

  • 说明

    • wait(&wstatus) 相当于 waitpid(-1, &wstatus, 0)
    • 一个wait()只等待一个子进程结束
    • 若子进程未结束,则阻塞自己,直到有进程退出
    • 若子进程已经结束,调用wait依然可以回收

部分笔记来源:mooc

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/882622.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号