linux进程控制

1. 创建一个子进程

  • 程序demo

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

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

    #include 
    #include 
    #include 
    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. 进程间共享

物理内存共享模式:读时共享,写时复制。
linux进程控制_第1张图片

  • 进程共享验证程序

    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 
    	#include 
    	#include 
    	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 
#include 
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 
    #include 
    #include 
    #include 
    #include 
    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 ...
    

你可能感兴趣的:(linux进程,linux,unix,服务器)