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

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步

void create_daemon();

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

进程组:一个进程组中包含好几个进程或者一个进程,拥有进程组ID,进程组ID就是进程组组长的ID。
会话组:会话组是一个或者几个进程组的集合,通常一个会话组开始于一个用户的登录,结束于用户的退出,
setsid()作用:让进程摆脱原进程组,会话组,以及终端的控制。

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

答:fork之后的函数,无论多进程还是单进程,父进程与子进程的运行顺序是不确定的,由内核的调度算法来确定。
vfork之后的函数就可以保证子进程先执行。具体代码可以浏览我的这篇博客:http://blog.chinaunix.net/uid-30131847-id-5137459.html

Q5:有一个全局变量 i 的初值为5,父进程对其进行加1操作,子进程看到的 i 的值是多少?
答:对于这个问题,fork()和vfork()得到的结果是不一样的。

int globvar = 6;
int main(int argc,char *argv[])
{
int pid;
int var = 5;
printf("now var is %d ,globvar is %d\n",var,globvar);
// pid = fork();
pid = vfork();
switch(pid)
{
case 0:
var++;
globvar++;
printf("child process var is %d, globvar is %d\n",var,globvar);
exit(0);
default:
var++;
globvar++;
printf("father process var is %d, globvar is %d\n",var,globvar);
exit(0); }
exit(0); }

fork的执行结果:
now var is 5 ,globvar is 6 //fork函数子进程继承父进程的全局和局部变量之后,分别执行各自的代码,
father process var is 6, globvar is 7 //所以因为初始变量相同,执行的程序也相同,他们的值也相同
child process var is 6, globvar is 7

vfork的执行结果: //vfork函数保证子进程先执行,由于它在父进程地址上运行,所以它先对两个变量的改变对于
now var is 5 ,globvar is 6 //父进程是可见的,子进程运行完之后,父进程得到已经被改变一次的变量值继续运行。
child process var is 6, globvar is 7
father process var is 7, globvar is 8
fork()函数的一瞬间全局变量和局部变量已经被子进程继承,以后他们运行在不同的地址空间,父进程更改,对于子进程是不可见的。
vfork()函数虽然子进程运行在父进程的地址空间上,但是vfork()保证了子进程的优先运行,应此父进程更改全局变量,子进程看不到。

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. 关于URL encode和parse

    from urllib import parses = 'https://www.baidu.com/s?ie=utf-8&f=3&rsv_bp=1&tn=baidu& ...

  2. GIS应用|快速搭建REST地图服务

    SuperMap Online云存储作为您的"在线GIS云盘",除了可以在云端存储GIS数据,还可以将数据直接发布多种REST服务,为您节省购买和部署SuperMap iServe ...

  3. 鸿蒙内核源码分析(挂载目录篇) | 为何文件系统需要挂载 | 百篇博客分析OpenHarmony源码 | v65.01

    百篇博客系列篇.本篇为: v65.xx 鸿蒙内核源码分析(挂载目录篇) | 为何文件系统需要挂载 | 51.c.h.o 文件系统相关篇为: v62.xx 鸿蒙内核源码分析(文件概念篇) | 为什么说一 ...

  4. Linux命令行:free

                  total        used        free      shared  buff/cache   availableMem:           251G   ...

  5. ORACLE 坏块的模拟和查看

    坏块的模拟和查看使用bbed工具修改数据文件的块,然后使用dbv和rman工具查看坏块. 1.创建数据:根据dbv查看没有坏块Total Pages Marked Corrupt : 0create ...

  6. windows中抓包命令,以及保存为多个文件的方法

    本文主要介绍windows中抓包命令,以及保存为多个文件的方法 说一说保存为多个文件存储数据包这个问题的由来,一般如果长时间抓包,有可能需要等上几个小时,因为这个时候抓包的内容都是存放在内存中的,几个 ...

  7. 使用Mybatis的一些基本配置及Mybatis与数据库交互测试验证

    1.简介 什么是MyBatis? MyBatis 是一款优秀的持久层框架,它支持定制化 SQL.存储过程以及高级映射.MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集.My ...

  8. CF850E Random Elections 题解

    题目传送门 题目大意 没法描述,过于繁杂. 思路 果然自己是个菜鸡,只能靠读题解读题,难受极了,其实不是很难自己应该做得出来的....哎.... 不难发现可以统计 \(A\) 获胜的情况乘上 \(3\ ...

  9. 简单几步零成本使用Vercel部署OneIndex 无需服务器搭建基于OneDrive的网盘

    前提 你需要一个OneDrive账号,必须管理员开放API 需要已安装Node.js 拥有Github账号,没有就注册一个 魔法上网环境(看情况) 注册应用 登录https://portal.azur ...

  10. ORM框架查询数据库时返回指定的字段

    django model.objects.filter() 查询指定字段 1.model.objects.filter().values('field_name'),单个字段 2.model.obje ...