• 12进程


    这节主要介绍,父子进程共享文件、fork基于的copy on write、exit(0)与_exit(0)的区别、atexit()终止处理程序。

    首先父子进程共享文件:

    直接献上一个例子:

    #include <unistd.h>
    #include <sys/stat.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    
    #include <stdlib.h>
    #include <stdio.h>
    #include <errno.h>
    #include <string.h>
    #include <signal.h>
    
    
    #define ERR_EXIT(m) 
    	do 
    	{ 
    		perror(m); 
    		exit(EXIT_FAILURE); 
    	} while(0)
    
    int main(int argc, char *argv[])
    {
    	signal(SIGCHLD, SIG_IGN);
    	printf("before fork pid = %d
    ", getpid());
    	int fd;
    	fd = open("test.txt", O_WRONLY); //在父进程中打开一个文件
    	if (fd == -1)
    		ERR_EXIT("open error");	
    	pid_t pid;
    	pid = fork();
    	if (pid == -1)
    		ERR_EXIT("fork error");
    
    	if (pid > 0)
    	{
    		printf("this is parent pid=%d childpid=%d
    ", getpid(), pid);
    		write(fd, "parent", 6);  //从父进程中向文件写
    		sleep(3);
    	}
    	else if (pid == 0)
    	{
    		printf("this is child pid=%d parentpid=%d
    ", getpid(), getppid());
    		write(fd, "child", 5);   //从子进程中向文件写
    	}
    	return 0;
    }
    

    可以看出,在子进程中不用重新打开文件,直接利用父进程中的文件描述符就可以对文件进行操作,这里值得注意的是有可能父进程先写进去子进程再写的时候直接把

    父进程写的内容给覆盖了,这是犹豫子进程写的时候父进程可能已经结束,这是用sleep控制一下会看出效果,这个大家自己动手试一试。

    fork的copy on write特性:

    意思就是父子进程各自都有自己的地址空间,但是都共享一些初始未变的东西,当子进程中有改变的时候就会拷贝一份放到自己的地址空间中去,看例子:

    #include <unistd.h>
    #include <sys/stat.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    
    #include <stdlib.h>
    #include <stdio.h>
    #include <errno.h>
    #include <string.h>
    #include <signal.h>
    
    #define ERR_EXIT(m) 
    	do 
    	{ 
    		perror(m); 
    		exit(EXIT_FAILURE); 
    	} while(0)
    
    int gval = 100;
    
    int main(int argc, char *argv[])
    {
    	signal(SIGCHLD, SIG_IGN);
    	printf("before fork pid = %d
    ", getpid());
    	
    	pid_t pid;
    	pid = fork();
    	if (pid == -1)
    		ERR_EXIT("fork error");
    
    	if (pid > 0)
    	{
    		sleep(1);
    		printf("this is parent pid=%d childpid=%d gval=%d
    ", getpid(), pid, gval);
    		sleep(3);
    	}
    	else if (pid == 0)
    	{
    		gval++;
    		printf("this is child pid=%d parentpid=%d gval=%d
    ", getpid(), getppid(), gval);
    	}
    	return 0;
    }
    

    打印的结果:父进程还是100而子进程是101。

    exit(0)与_exit(0)的区别:

    1、exit(0)是C函数库提供的,而_exit(0)是linux系统的系统调用。

    2、

    这个就是执行时候的区别,_exit(0)会直接去到内核中去,而exit(0)会调用终止程序和清除i/o缓冲。

    int main(int argc, char *argv[])
    {
    	printf("hello world");
    	//fflush(stdout);
    	//_exit(0);
    	exit(0);
    }
    
    int main(int argc, char *argv[])
    {
    	printf("hello world");
    	//fflush(stdout);
    	_exit(0);
    	//exit(0);
    }
    
    int main(int argc, char *argv[])
    {
    	printf("hello world
    ");
    	//fflush(stdout);
    	_exit(0);
    	//exit(0);
    }
    
    int main(int argc, char *argv[])
    {
    	printf("hello world");
    	fflush(stdout);
    	_exit(0);
    	//exit(0);
    }
    

    可以看出请没清缓冲去的区别,这里 和fflush都是有清的功能,只是为了让大家了解一下。

    下面是终止处理程序,简单了解一下:

    #include <unistd.h>
    #include <sys/stat.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    
    #include <stdlib.h>
    #include <stdio.h>
    #include <errno.h>
    #include <string.h>
    #include <signal.h>
    
    
    #define ERR_EXIT(m) 
    	do 
    	{ 
    		perror(m); 
    		exit(EXIT_FAILURE); 
    	} while(0)
    
    void my_exit1(void)
    {
    	printf("my exit1 ...
    ");
    }
    
    void my_exit2(void)
    {
    	printf("my exit2 ...
    ");
    }
    
    int main(int argc, char *argv[])
    {
    	//下面是两次安装
    	atexit(my_exit1);
    	atexit(my_exit2);
    	_exit(0);
    }
    

    可以看出终止处理程序的调用次序和安装次序正好相反,了解了解即可。

    最后给出一个有意思的小程序,供大家分享一下父子进程的运行流程:

    int main(int argc, char *argv[])
    {
    	fork();
    	fork();
    	fork();
    	printf("ok
    ");
    	return 0;
    }
    

    运行一下看看能打印多少个OK,自己动手画一下运行线图可以理解清楚。

    答案是:8个。

  • 相关阅读:
    任意文件读取与下载漏洞
    命令执行与代码执行漏洞原理
    安全面试知识汇总
    科学使用Github(gayhub)搜索想要的项目
    业务逻辑漏洞--注册-登录-改密码页面总结
    Linux提权之SUID提权
    攻防世界XCTF--伪造请求头XFF和Referer(第九题)
    攻防世界XCTF--两种传输方式get_post(第八题)
    攻防世界XCTF--一个简单的PHP后端验证(第七题)
    课时14.DTD文档声明上(掌握)
  • 原文地址:https://www.cnblogs.com/DamonBlog/p/4373495.html
Copyright © 2020-2023  润新知