(声明:本篇博客只是博主自己的理解,加以整理,目的是总结刚学过的进程知识,不一定绝对正确,非常愿意听客官您提出宝贵意见。)



Q1:进程中的全局数据段(全局变量),局部数据段(局部变量),静态数据段的分别位于哪个内存地址空间?

:对于进程的概念,我把它理解一个可执行程序进行的实体,我们c语言代码在变成可执行文件的过程中都会经历下面4步(以我们大家接触的第一个c语言程序“helloworld”为例)

(1)预处理:将中的内容和一些宏定义展开,将if,else等判断处理,将注释转化为空格等,我们可以执行 gcc -E helloworld.c -o helloworld.i  来获取预处理之后的文件,在hellowrold.i文件末尾,我们可以找到我们短短的几行程序。

(2)编译:编译的过程主要是编译器对我们代码的语法,词法分析,我们编译器的报错机制就是这部分的体现。同样,我们可以执行 gcc -S helloworld.c -o helloworld.s 同样我们可以看到它的汇编指令(编译的结果得到的是汇编指令)。当然我不懂汇编指令。就不多说了。

(3)汇编:汇编的过程是将我们的汇编指令转化为我们的计算机能够识别的机器指令。

(4)链接:生成我们的可执行文件的过程,可执行的概念是可以被加载或者可以被拷贝到存储器中等待执行。

   如果我们运行它,它就会成为一个进程,程序到进程大概是这个过程,首先内核将程序读入内存,并且内存为其分配相应的内存空间,然后内核为其分配pid,和其他所需资源,接着内核会保存pid以及相应的状态信息,并且把进程放到运行队列里等待执行,要是被操作系统调度使用,进程就建立。下来我们进入我们要回答的问题:进程的内存映像是指程序在内存中的状态,也可以说在内存中如何存放的。linux系统的内存映像一般是这样,从内存的地址由低到高依次为:代码段,静态数据段(以被初始化的变量,全局变量和静态变量),动态数据段(malloc),堆段,栈段,命令行参数和环境量。

Q2:列举子进程的父进程的异同。

:fork()函数是我们用户能唯一使用的创建进程的方式,在fork()和vfork()中,子进程和父进程的特点是不同的:


子进程和父进程相同点 子进程和父进程不同点
fork() 子进程继承父进程的下列信息:

1)用户ID,组ID,当前工作目录,根目录,打开的文件

2)创建文件时使用的屏蔽字,信号屏蔽字,上下文环境,等
1)有它自己的pid

2)不同的父进程ID

3)子进程共享父进程打开的文件描述符,但父进程对文件描述符的改变不会影响子进程中的文件描述符。

4)子进程不继承父进程设置的文件锁和警告。
vfork()

与fork()不同
同样子进程会继承这些父进程的信息   除了上面说的之外,补充一点:

vfork()之后并不会将父进程的地址空间完全复制给子进程,子进程会在父进程的地址空间上运行,这一点和线程的概念是相似的    

Q3:如何创建一个后台进程(守护进程)?

:对于守护进程的概念,我自己认为linux下最简单的例子就是服务了,比如我们安装vsftp服务,并且给它设置enable(开机自动启动),当我们的系统启动之后,它就已经正常工作了,只要我们不关机,它就一直在后台运行,它是独立于我的控制终端的;还有我们要把自己的一块磁盘挂载到某个mountpoint上,但是每次自己手动挂载都很麻烦,我们就可以设置开机自动挂载,vim /etc/fstab 文件,再次开机之后,它就已经挂载好了。我们的计算机要是要提供某种服务,就必须会创建守护进程。步骤大概有5步

点击(此处)折叠或打开

  1. void create_daemon();
  2. void create_daemon()
  3. {
  4. int pid;
  5. int i;
  6. pid = fork();                                        1 //先让父进程fork一个进程
  7. if(pid > 0)                                            //结束父进程,让子进程脱离当前进程独立
  8. exit(0);
  9. setsid();                                            2 //设置子进程为会话组组长.
  10. pid = fork();                                        3 //再次fork一个子进程,并让父进程退出。
  11. if(pid > 0)                                          4 //禁止进程重新打开控制终端,现在进程已经成为一个无终端的会话组组长,但是它可以申请来打                                                             开一个终端,,为了避免这种情况,可以通过进程不再是会话组组长实现,所以再次fork;
  12. exit(0);
  13. for(i = 0;i < NOFILE;close(i++))                      5 //关闭继承的父进程的所有打开的文件描述符
  14. ;
  15. umask(0);                                             //将文件创建时屏蔽字设置为零(权限设置为777),因为从父进程继承的东西可能屏蔽掉某种权限
  16. chdir("/");                                           //当守护进程的工作目录在一个装配文件目录中时,它不可卸载,一般需要将根目录设置为工作目录
  17. signal(SIGCHLD,SIG_IGN);                               //这样可以保证子进程不会产生僵尸进程。
  18. }
  19. int main(int argc,char *argv[])
  20. {
  21. printf("create a daemon\n");
  22. create_daemon();
  23. while(1)                                                //守护进程我们通常让它周期的执行某种任务,所以我们会让它在while(1)循环中执行
  24. {
  25. sleep(1);
  26. }
  27. }

进程组:一个进程组中包含好几个进程或者一个进程,拥有进程组ID,进程组ID就是进程组组长的ID。

会话组:会话组是一个或者几个进程组的集合,通常一个会话组开始于一个用户的登录,结束于用户的退出,

setsid()作用:让进程摆脱原进程组,会话组,以及终端的控制。

Q4:在多进程中,父子进程的运行顺序是怎样的。

答:fork之后的函数,无论多进程还是单进程,父进程与子进程的运行顺序是不确定的,由内核的调度算法来确定。

     vfork之后的函数就可以保证子进程先执行。具体代码可以浏览我的这篇博客:http://blog.chinaunix.net/uid-30131847-id-5137459.html

Q5:有一个全局变量 i 的初值为5,父进程对其进行加1操作,子进程看到的 i 的值是多少?

答:对于这个问题,fork()和vfork()得到的结果是不一样的。

点击(此处)折叠或打开

  1. int globvar = 6;
  2. int main(int argc,char *argv[])
  3. {
  4. int pid;
  5. int var = 5;
  6. printf("now var is %d ,globvar is %d\n",var,globvar);
  7. // pid = fork();
  8. pid = vfork();
  9. switch(pid)
  10. {
  11. case 0:
  12. var++;
  13. globvar++;
  14. printf("child process var is %d, globvar is %d\n",var,globvar);
  15. exit(0);
  16. default:
  17. var++;
  18. globvar++;
  19. printf("father process var is %d, globvar is %d\n",var,globvar);
  20. exit(0);
  21. }
  22. exit(0);
  23. }
  24. fork的执行结果:
  25. now var is 5 ,globvar is 6                          //fork函数子进程继承父进程的全局和局部变量之后,分别执行各自的代码,
  26. father process var is 6, globvar is 7               //所以因为初始变量相同,执行的程序也相同,他们的值也相同
  27. child process var is 6, globvar is 7
  28. vfork的执行结果:                                     //vfork函数保证子进程先执行,由于它在父进程地址上运行,所以它先对两个变量的改变对于
  29. now var is 5 ,globvar is 6                          //父进程是可见的,子进程运行完之后,父进程得到已经被改变一次的变量值继续运行。
  30. child process var is 6, globvar is 7
  31. father process var is 7, globvar is 8

fork()函数的一瞬间全局变量和局部变量已经被子进程继承,以后他们运行在不同的地址空间,父进程更改,对于子进程是不可见的。

vfork()函数虽然子进程运行在父进程的地址空间上,但是vfork()保证了子进程的优先运行,应此父进程更改全局变量,子进程看不到。

阅读(1) | 评论(0) | 转发(0) |

给主人留下些什么吧!~~
评论热议

版权声明:本文为博主原创文章,未经博主允许不得转载。

linux&c 进程控制 课后习题的更多相关文章

  1. linux&c 进程控制 课后习题

    (声明:本篇博客只是博主自己的理解,加以整理,目的是总结刚学过的进程知识,不一定绝对正确,非常愿意听客官您提出宝贵意见.) Q1:进程中的全局数据段(全局变量),局部数据段(局部变量),静态数据段的分 ...

  2. Linux&C 线程控制 课后习题

    Q1:多线程与多进程相比有什么优势? 多进程程序耗费的资源大,因为fork()的时候子进程需要继承父进程的几乎所有东西,但是多线程程序线程只继承一部分,即自己的私有数据,例如自己的线程ID,一组寄存器 ...

  3. Linux&C 线程控制 课后习题

    Q1:多线程与多进程相比有什么优势? 多进程程序耗费的资源大,因为fork()的时候子进程需要继承父进程的几乎所有东西,但是多线程程序线程只继承一部分,即自己的私有数据,例如自己的线程ID,一组寄存器 ...

  4. linux中进程控制

    1.进程标识 每个进程都有一个非负整型表示的唯一的进程ID.进程ID标识符总是唯一的.  虽然进程ID是唯一的,但某个ID被回收后,ID号是可以复用的. ID为0的进程通常是调度进程(其常常被称交换进 ...

  5. Linux/UNIX进程控制(1)

    进程控制(1) 进程标识符 每一个进程都有肺腑的整形表示唯一的进程ID.按一个进程终止后,其进程ID就能够再次使用了.例如以下是几个典型进程的ID及其类型和功能. ID     进程名         ...

  6. Linux C 程序 进程控制(17)

    进程控制 1.进程概述现代操作系统的特点在于程序的并行执行.Linux是一个多用户多任务的操作系统.ps .pstree 查看进程进程除了进程id外还有一些其他标识信息,可以通过相应的函数获得.// ...

  7. 【linux草鞋应用编程系列】_2_ 环境变量和进程控制

    一. 环境变量     应用程序在执行的时候,可能需要获取系统的环境变量,从而执行一些相应的操作.     在linux中有两种方法获取环境变量,分述如下.   1.通过main函数的参数获取环境变量 ...

  8. 【Linux程序设计】之进程控制&守护进程

    这个系列的博客贴的都是我大二的时候学习Linux系统高级编程时的一些实验程序,都挺简单的. 实验题目:Linux环境下的进程控制 实验目的:熟悉并掌握Linux环境下进程的相关函数的应用:守护进程的概 ...

  9. linux进程及进程控制

    Linux进程控制   程序是一组可执行的静态指令集,而进程(process)是一个执行中的程序实例.利用分时技术,在Linux操作系统上同时可以运行多个进程.分时技术的基本原理是把CPU的运行时间划 ...

随机推荐

  1. 手把手教你调试SpringBoot启动 IoC容器初始化源码,spring如何解决循环依赖

    授人以鱼不如授人以渔,首先声明这篇文章并没有过多的总结和结论,主要内容是教大家如何一步一步自己手动debug调试源码,然后总结spring如何解决的循环依赖,最后,操作很简单,有手就行. 本次调试 是 ...

  2. disruptor笔记之三:环形队列的基础操作(不用Disruptor类)

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...

  3. 关于Servlet

    Servlet与CGI CGI(Common Gateway Interface),早期的Web服务器技术.执行模式:将服务端的资源基于进程运行. Servlet:运行模式改为单进程多线程的形式,利用 ...

  4. 踩坑系列《十》Python pip 安装问题一站式解决

    在使用Python编程语言时,难免要安装第三方库 安装一般都是在cmd命令行窗口安装 1.常规安装 ,在窗口输入 pip install 你要下载的库 这种方式一般网速比较慢,毕竟是从国外下载的 2. ...

  5. 【原创】xenomai 在X86平台下中断响应时间测试

    1.中断响应时间 实时操作系统的意义就在于能够在确定的时间内处理各种突发的事件,而中断这些事件.系统抢占调度的触发点,因而衡量嵌入式实时操作系统的最主要.最具有代表性的性能指标参数无疑是中断响应时间. ...

  6. 都 2021 年了,Serverless 能取代微服务吗?

    来源 | Serverless 公众号 编译 | OrangeJ 作者 | Mariliis Retter "Serverless 能取代微服务吗?" 这是知乎上 Serverle ...

  7. 题解「2017 山东一轮集训 Day1 / SDWC2018 Day1」Set

    题目传送门 题目大意 给出一个长度为 \(n\) 的数组,选出一些数异或之和为 \(s1\),其余数异或之和为 \(s2\),求 \(s1+s2\) 最大时 \(s1\) 的最小值. 思路 你发现如果 ...

  8. 洛谷3119 草鉴定(tarjan)

    题目大意 约翰有\(n\)块草场,编号\(1\)到\(n\),这些草场由若干条单行道相连.奶牛贝西是美味牧草的鉴赏家,她想到达尽可能多的草场去品尝牧草. 贝西总是从\(1\)号草场出发,最后回到\(1 ...

  9. Linux基本命令 和 Regex 正则表达式

    Linux基本命令 和 Regex 正则表达式 Regex 基本语法 常用匹配规则 [aeiouAEIOU] # 从中随机选择一个 [0-9]{4} # 从中选择4个 .* # 匹配任意字符 \w # ...

  10. C#并行编程:Parallel的使用

    前言:在C#的System.Threading.Tasks 命名空间中有一个静态的并行类:Parallel,封装了Task的使用,对于执行大量任务提供了非常简便的操作.下面对他的使用进行介绍. 本篇内 ...