IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 系统运维 -> linux进程控制 -> 正文阅读

[系统运维]linux进程控制

1. 创建一个子进程

  • 程序demo

    #include <sys/types.h>
    #include <unistd.h>
    pid_t fork(void);  		// 创建一个子进程
    pid_t getpid(void);  	// 获取当前进程的id
    pid_t getppid(void); 	// 获取当前进程父进程的id
    
  • fork函数返回值:
    失败 返回 -1
    成功 两次返回
    ? 父进程返回子进程的 pid_t
    ? 子进程返回 0

  • 创建一个子进程的程序:

    #include <stdio.h>
    #include <unistd.h>
    #include <stdlib.h>
    int main()
    {
        printf("Begin ..\n");
        pid_t pid = fork();
        if (pid < 0) {
            perror("fork err\n");
            exit(1);
        }
        if (pid == 0) {
            printf("I am a Child, pid = %d, ppid = %d \n", getpid(), getppid());
        } else if (pid > 0) {
            printf("I am a Parent, childpid = %d, selfpid = %d, ppid = %d \n", 
            	pid, getpid(), getppid());
            sleep(1); // 如果不加sleep,父进程先消亡,此时子线程会变成孤儿线程
        }
        printf("End ...\n");
        return 0;
    }
    
  • 输出结果

    Begin ..
    I am a Parent, childpid = 73714, selfpid = 73713, ppid = 73479 
    I am a Child, pid = 73714, ppid = 73713 
    End ...
    End ...
    
  • 为什么会执行两次printf(“End …\n”)函数呢?
    在fork函数生成子进程之后,父进程和子进程都会执行fork语句之后的代码。

  • 补充:linux查看进程信息的命令
    查看进程信息:ps aux
    查看进程组信息:ps ajx
    给进程发送一个信号:kill
    杀死一个进程:kill -9 pid

2. 创建多个子进程

  • 创建多个子进程的程序:

    int main()
    {
        printf("Begin ..\n");
        for (int i = 0; i < 5; i++) {
            pid_t pid = fork();
            if (pid < 0) {
                perror("fork err\n");
                exit(1);
            }
            if (pid == 0) {
                printf("I am a Child, pid = %d, ppid = %d \n", getpid(), getppid());
                break; // 子进程退出for循环
            } else if (pid > 0) {
                printf("I am a Parent, childpid = %d, selfpid = %d, ppid = %d \n", 
                	pid, getpid(), getppid());
                sleep(1);
            }
        }
        printf("End ...\n");
        return 0;
    }
    
  • 执行结果:

    Begin ..
    I am a Parent, childpid = 74179, selfpid = 74178, ppid = 73479 
    I am a Child, pid = 74179, ppid = 74178 
    End ...
    I am a Parent, childpid = 74182, selfpid = 74178, ppid = 73479 
    I am a Child, pid = 74182, ppid = 74178 
    End ...
    I am a Parent, childpid = 74192, selfpid = 74178, ppid = 73479 
    I am a Child, pid = 74192, ppid = 74178 
    End ...
    I am a Parent, childpid = 74202, selfpid = 74178, ppid = 73479 
    I am a Child, pid = 74202, ppid = 74178 
    End ...
    I am a Parent, childpid = 74203, selfpid = 74178, ppid = 73479 
    I am a Child, pid = 74203, ppid = 74178 
    End ...
    End ...
    

如果子进程不及时退出for循环,子进程也会生成子进程,程序执行完不单单是生成5个子进程了。

3. 进程间共享

物理内存共享模式:读时共享,写时复制。
在这里插入图片描述

  • 进程共享验证程序

    int main()
    {
        printf("Begin ..\n");
        int var = 100;
        pid_t pid = fork();
        if (pid == 0) {
            printf("I am a Child, var = %d, pid = %d, ppid = %d \n",
            	var, getpid(), getppid());
            var = 0; // 子进程修改 var 变量的值
            printf("I am a Child, var = %d, pid = %d, ppid = %d \n",
            	var, getpid(), getppid());
        } else if (pid > 0) {
            sleep(3);
            printf("I am a Parent, var = %d, childpid = %d, selfpid = %d, \
            	ppid = %d \n", var, pid, getpid(), getppid());
        }
        printf("End ...\n");
        return 0;
    }
    
  • 输出结果:

    Begin ..
    I am a Child, var = 100, pid = 74447, ppid = 74446 
    I am a Child, var = 0, pid = 74447, ppid = 74446 
    End ...
    I am a Parent, var = 100, childpid = 74447, selfpid = 74446, ppid = 73479 
    End ...
    

4. execl函数族

  • execl函数的作用:

    fork创建子进程后执行和父进程相同的程序,子进程可以调用execl函数执行另一个程序。当一个进程调用execl函数时,该进程的用户空间代码和数据完成被新程序替换,从新程序的启动例程开始执行。

  • 常用的execl函数

    int execl(const char *path, const char *arg, .../* (char  *) NULL */);
    int execlp(const char *file, const char *arg, .../* (char  *) NULL */);
    

    execl 执行其它程序
    execlp 执行其它程序时,使用PATH变量,执行的程序可以不用加路径
    ? file 要执行的程序
    ? arg 参数列表,最后一个参数以NULL结尾
    ? 返回值,只有失败才返回

  • 程序demo

    int main()
    {
    	//execl("/bin/ls", "ls", "-l", "--color=auto", NULL);
    	execlp("ls", "ls", "-l", "--color=auto", NULL);
    	perror("exec err");
    	return 0;
    }
    

    注:第二个 “ls” 是一个无用的参数占位符

5. 孤儿进程与僵尸进程

孤儿进程:父进程死了,子进程被init进程领养
僵尸进程:子进程死了,父进程没有回收子进程的资源(PCB)
如何回收僵尸进程:杀死父进程

  • 孤儿进程demo

    	#include <stdio.h>
    	#include <unistd.h>
    	#include <stdlib.h>
    	int main()
    	{
    	    printf("Begin ..\n");
    	    pid_t pid = fork();
    	    if (pid < 0) {
    	        perror("fork err\n");
    	        exit(1);
    	    }
    	    if (pid == 0) {
    	        printf("I am a Child, pid = %d, ppid = %d \n", getpid(), getppid());
    	        sleep(5);
    	    } else if (pid > 0) {
    	        printf("I am a Parent, childpid = %d, selfpid = %d, ppid = %d \n", 
    	        	pid, getpid(), getppid());
    	    }
    	    printf("End ...\n");
    	    return 0;
    	}
    
  • 输出结果

    Begin ..
    I am a Parent, childpid = 74966, selfpid = 74965, ppid = 73479 
    End ...
    [zhpng@iZuf6ddpzz3ipktm5kj01cZ webserver]$ I am a Child, pid = 74966, ppid = 1 
    End ...
    

6. 子进程回收

#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *wstatus);
pid_t waitpid(pid_t pid, int *wstatus, int options);

wait函数回收子进程,查看子进程的死亡原因。

  • 作用
    阻塞等待
    回收子进程资源
    查看子进程死亡原因

  • pid_t wait(int *status)
    status 出参,死亡原因
    返回值
    ?成功 返回终止的子进程ID
    ?失败 返回 -1

  • 子进程死亡原因
    正常死亡:WIFEXITED,如果WIFEXITED为真,使用WEXITSTATUS得到退出状态
    非正常死亡:WIFSIGNALED,如果WIFSIGNALED为真,使用WEXITSTATUS得到信号

  • wait函数回收多个子进程demo

    #include <stdio.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <sys/wait.h>
    int main()
    {
        printf("Begin ..\n");
        int i = 0;
        pid_t pid;
        for (i = 0; i < 5; i++) {
            pid = fork();
            if (pid == 0) {
                printf("I am child, pid = %d \n", getpid());
                break;
            }
        }
        sleep(i);
        if (i == 5) {
            for (i = 0; i < 5; i++) {
                pid_t wpid = wait(NULL);
                printf("wpid = %d \n", wpid);
                sleep(1);
            }
            sleep(1);
        }
        printf("End ...\n");
        return 0;
    }
    
  • 输出结果

    Begin ..
    I am child, pid = 76074 
    I am child, pid = 76075 
    I am child, pid = 76071 
    I am child, pid = 76072 
    I am child, pid = 76073 
    End ...
    End ...
    End ...
    End ...
    End ...
    wpid = 76071 
    wpid = 76072 
    wpid = 76073 
    wpid = 76074 
    wpid = 76075 
    End ...
    
  系统运维 最新文章
配置小型公司网络WLAN基本业务(AC通过三层
如何在交付运维过程中建立风险底线意识,提
快速传输大文件,怎么通过网络传大文件给对
从游戏服务端角度分析移动同步(状态同步)
MySQL使用MyCat实现分库分表
如何用DWDM射频光纤技术实现200公里外的站点
国内顺畅下载k8s.gcr.io的镜像
自动化测试appium
ctfshow ssrf
Linux操作系统学习之实用指令(Centos7/8均
上一篇文章      下一篇文章      查看所有文章
加:2021-11-14 22:09:38  更:2021-11-14 22:11:39 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/15 23:22:34-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码