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



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. 谷歌浏览器chrome安装插件报"程序包无效: CRX_HEADER_INVALID"错误

    今天参加需求评审,看到原来可以谷歌浏览器查看Axure原型文件,真是只有想不到,没有做不到(自己孤陋寡闻了,第一次接触Axure). 需求评审后,我百度"如何使用谷歌浏览器查看Axure原型 ...

  2. Ubuntu怎么开启/关闭防火墙

    在Ubuntu中,使用sudo ufw status命令查看当前防火墙状态. 不活动,是关闭状态. 在Ubuntu中,使用sudo ufw enable命令来开启防火墙. 在Ubuntu中,使用sud ...

  3. javascript/html 禁止图片缓存

    更新图片, 如果图片的url没有改变, 刷新页面之后图片会使用缓存的图片 Solutions: * js改变图片链接 (添加get参数) // 假设当前这个图片的dom对象为img img.src + ...

  4. pycharm向GitHub提交代码

    设置为自动add commit代码 push代码 查看github,看到提交记录

  5. python全局变量的定义

    第一:如定义在类或者函数体外,在函数或者类中引用需要用到 global声明 temp_t = "ceshi" def tmp1(): global temp_t temp_t =1 ...

  6. Phalcon如何切换数据库《Phalcon入坑指南系列 三》

    本系列目录 一.Phalcon在Windows上安装 <Phalcon入坑指南系列 一> 二.Phalcon入坑必须知道的功能(项目配置.控制器.模型.增.删.改.查) 三.Phalcon ...

  7. P7046-「MCOI-03」诗韵【SAM,倍增,树状数组】

    正题 题目链接:https://www.luogu.com.cn/problem/P7046 题目大意 给出一个长度为 \(n\) 的字符串,然后 \(m\) 次把它的一个子串加入集合.如果一个字符串 ...

  8. bug 找不到或无法加载主类main.java.*

    开发时遇到的的一个问题,不知道是什么引起的,一个maven springboot 的项目,主类启动的时候报错,说没找到 主类,起先怀疑是springboot的问题,随手写一个单独的类,有main方法, ...

  9. Vite插件开发纪实:vite-plugin-monitor(上)

    背景 最近在webpack项目里接入了Vite(dev mode),为开发提效.效果是真的猛. 项目启动速度提升70%-80%,HMR直接碾压webpack dev server 为了更加精准的计算收 ...

  10. Java 开发最容易写的 10 个bug

    原文链接:10 个让人头疼的 bug 那个谁,今天又写 bug 了,没错,他说的好像就是我...... 作为 Java 开发,我们在写代码的过程中难免会产生各种奇思妙想的 bug ,有些 bug 就挺 ...