进程的创建

一、实验目的及要求

(1)加深对进程概念的理解,明确进程与程序的区别,并认识并发执行的实质。

(2)掌握linux中进程的创建及撤消,理解进程的生命周期。

(3)理解进程同步工作的原理,掌握linux中wait()、exit ()、sleep()实现进程的同步。

二、实验工具

计算机、VMware Workstation Pro

三、实验内容及步骤

一、安装编译器GCC

Linux下C语言编程常用的编辑器是vim,编译器一般用gcc,编译链接程序用make,跟踪调试一般使用gdb

在Ubuntu上安装GCC

在默认的Ubuntu资源库中,有一个名为build-essential的元包,其包含GCC和其他各种编译器,如g++和make。我们也可以通过安装build-essentials包来安装GCC。一旦我们安装了build-essential包,GCC也就安装在我们的系统中了。
按照以下步骤进行
1安装gcc: sudo apt-get install gcc

安装到最后出现一些错误:

(2)使用命令更新软件包列表。
sudo apt update

3使用命令安装 build-essential 包。
sudo apt install build-essential

它与我们系统中的其他编译器一起安装GCC。

(4)验证GCC安装的情况

我们用下面的命令来验证GCC是否安装成功。
gcc --version
  如果GCC成功安装,我们会得到一个输出,包括版本和其他关于GCC的信息。输出:

 二、

  • 编程实现
  1. 进程的创建及终止

(1)编写三个程序实现进程的创建及撤消。要求分别调用fork()、vfork()实现进程的创建,调用exit()终止进程,调用exec()为进程指定新的运行程序。

(2)调试并分析结果

任务一:编写一段程序,使用系统调用fork()创建两个子进程。当此程序运行时,在系统中有一个父进程和两个子进程活动。让每一个进程在屏幕上显示一个字符,父进程显示字符“a”,子进程分别显示字符“b”和“c”。试观察记录屏幕上的显示结果,并分析原因。

(1)首先创建一个.c文件

2然后代码编辑

(3)接着使用gcc 1.c -o 1编辑

该命令是直接进行链接生成可执行程序, 链接之前的三步会自动执行。

 (4)最后执行运行出结果

(5)分析:

分析:从进程执行并发来看,输出abc的排列都是有可能的。

原因:fork()创建进程所需的时间虽然可能多于输出一个字符的时间,但各个进程的时间片的获得却不是一定是顺序的,所以输出abc的排列都是有可能的。而从进程并发执行来看,各种情况都有可能。上面的三个进程没有同步措施,所以父进程与子进程的输出内容会叠加在一起。输出次序带有随机性。

任务二:调用fork()编写一段程序,在子进程中修改变量,并在父进程中观察其影响。

利用fork() 函数创建进程
用fork ()函数创建进程时,语句调用系列如下:

Pit_t fork(void); fork()函数是一个单调用双返回的函数,也就是说,该函数有父进程调用,执行时,在父进程中返回子进程标识,在子进程中返回0。fork()调用后,子进程是父进程的一个复制,都是从fork()调用语句开始执行。

(1)首先创建文件

(2)然后编辑代码

(3)接着使用gcc进行编辑

(4)最后执行出结果

fork(  )返回值意义如下:
0:在子进程中,pid变量保存的fork(  )返回值为0,表示当前进程是子进程。
>0:在父进程中,pid变量保存的fork(  )返回值为子进程的id值(进程唯一标识符)。
-1:创建失败。
如果fork( )调用成功,它向父进程返回子进程的PID,并向子进程返回0,即fork( )被调用了一次,但返回了两次。此时OS在内存中建立一个新进程,所建的新进程是调用fork( )父进程(parent process)的副本,称为子进程(child process)。子进程继承了父进程的许多特性,并具有与父进程完全相同的用户级上下文。父进程与子进程并发执行。

任务三:调用vfork()编写一段程序,在子进程中修改变量,并在父进程中观察其影响。

vfork()系统调用:

用vfork()函数创建进程时,通常使用exec()函数紧跟其后,以便为新创建进程指派另外一个可执行程序。用vfork()创建的新进程并不完全复制父进程的数据区。vork()与fork()另一个不同点表现在父子进程的执行顺序上。fork()不对父子进程的执行次序进行任何限制,而vfork()调用后,子进程先运行,父进程挂起,直到子进程调用exec()或exit()之后,父子进程的执行顺序才不再有限制。否则,如果子进程在调用exec()或exit()之前,父进程被激活,就会造成死锁。

(1)首先创建文件

(2)然后编辑代码

头文件 #include<unistd.h>

定义函数pid_t vfork(void);

(3)接着使用gcc进行编辑

(4)最后执行出结果

如果vfork()成功则在父进程会返回新建立的子进程代码(PID),而在新建立的子进程中则返回0。如果vfork失败则直接返回-1,失败原因存于errno中。

vfork()用法与fork()相似.但是也有区别,具体区别归结为以下3点:

①fork():子进程拷贝父进程的数据段,代码段。

vfork():子进程与父进程共享数据段.

②fork():父子进程的执行次序不确定.
vfork():保证子进程先运行,在调用exec或_exit之前与父进程数据是共享的,在它调用exec或_exit之后父进程才可能被调度运行。

③vfork()保证子进程先运行,在她调用exec或_exit之后父进程才可能被调度运行。如果在调用这两个函数之前子进程依赖于父进程的进一步动作,则会导致死锁。

④当需要改变共享数据段中变量的值,则拷贝父进程。

任务四:可以打印出传递给运行进程的参数和所使用的环境变量的程序

环境变量是指操作系统中用来指定操作系统运行环境的一下参数

特征:

字符串

有统一的格式: 名=值[:值]

值用来描述进程的环境信息

使用形式:与命令行参数类似

存储形式:与命令行参数类似,char* []数组,数组名 environ, 内部存储字符串, NULL做为哨兵

加载位置:与命令行参数类似,位于用户区, 高于stack区域 的起始位置

引入环境变量表:必须声明 环境变量 extern char** environ;

(1)首先创建文件

(2)然后编辑代码

 (3)接着使用gcc进行编辑

(4)结果:

主函数的参数(3个)

int main(int argc , char* argv[] , char* envp[])

int argc:参数个数(数组argv[]元素个数)

char* argv[]:参数内容(其中argv[0]=./main 运行程序名)

char* envp[]:环境变量

由于环境变量末尾为空指针,所以循环条件即为*environ!=NULL。

四、实验总结

 通过这次实验使我掌握了linux中进程的创建及撤消,wait()、exit()、sleep()实现进程的同步,理解了进程的生命周期进程同步工作及进程通信的原理。对系统调用的一些函数的使用加深了理解,对linux下进程的创建有了进一步的理解,对父子进程的同步产生的结果有了一定的认识。在老师的指导下,顺利地完成了本次实验,即使在有些地方还是不太明白,但经过不断的练习对进程创建会有新的认识的。

  • 6
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值