linux进程管理实验fork,实验四 Linux的系统调用和进程管理

本文详细介绍了如何在Linux环境下使用Vim编辑器进行代码编写,包括其工作模式和常用命令。接着讲解了GCC编译器的使用,包括基本选项和编译过程。此外,还探讨了GDB调试器的运用,如设置断点、查看变量值等。最后,文章通过实例展示了如何使用fork()系统调用来创建和控制进程,以及如何处理僵死进程,并讨论了进程间的互斥控制。
摘要由CSDN通过智能技术生成

实验目的:

通过实验掌握下列知识:

1、熟悉Linux下的编程环境Vi。

2、熟悉进程之间的等待,了解僵死进程。

3、使用Linux进程创建和控制,fork()系统调用的使用。

内容及步骤:

一、Vim编辑器的使用

vim是在Linux上被广泛使用的中英文编辑软件。vim是visual

editor的缩写,是Linux提供给用户的一个窗口化编辑环境。

进入vim,直接执行vim编辑程序即可。

例:$vim

test.c

显示器出现vim的编辑窗口,同时vim会将文件复制一份至缓冲区(buffer)。vim先对缓冲区的文件进行编辑,保留在磁盘中的文件则不变。编辑完成后,使用者可决定是否要取代原来旧有的文件。

1、vim的工作模式

vim提供二种工作模式:输入模式(insert

mode)和命令模式(command

mode)。使用者进入vim后,即处在命令模式下,此刻键入的任何字符皆被视为命令,可进行删除、修改、存盘等操作。要输入信息,应转换到输入模式。

(1)命令模式

在输入模式下,按ESC可切换到命令模式。命令模式下,可选用下列指令离开vi:

:q! 离开vi,并放弃刚在缓冲区内编辑的内容

:wq

将缓冲区内的资料写入磁盘中,并离开vi

:ZZ

同wq

:x

同wq

:w 将缓冲区内的资料写入磁盘中,但并不离开vi

:q

离开vi,若文件被修改过,则要被要求确认是否放弃修改的内容,此指令可与:w配合使用

(2)命令模式下光标的移动

H

左移一个字符

J

下移一个字符

K

上移一个字符

L

右移一个字符

0

移至该行的首

$

移至该行的末

^

移至该行的第一个字符处

H移至窗口的第一列

M

移至窗口中间那一列

L

移至窗口的最后一列

G

移至该文件的最后一列

W, W

下一个单词 (W 忽略标点)

B, B

上一个单词 (B 忽略标点)

+

移至下一列的第一个字符处

-

移至上一列的第一个字符处

(

移至该句首

)

移至该句末

{

移至该段首

}

移至该段末

NG

移至该文件的第n列

N+

移至光标所在位置之后第n列

n-

移至光标所在位置之前第n列

(3)输入模式

输入以下命令即可进入vi输入模式:

a(append)

在光标之后加入资料

A

在该行之末加入资料

i(insert)

在光标之前加入资料

I

在该行之首加入资料

o(open)

新增一行于该行之下,供输入资料用

O

新增一行于该行之上,供输入资料用

Dd

删除当前光标所在行

X

删除当前光标字符

X

删除当前光标之前字符

U

撤消

重做

F

查找

s

替换,例如:将文件中的所有"FOX"换成"duck",用":%s/FOX/duck/g"

ESC 离开输入模式

测试代码 Test.c文件

#include

int func(int

n)

{

int sum=0,i;

for(i=1; i<=n; i++)

{

sum+=i;

}

return sum;

}

int

main()

{

int i;

long result = 0;

for(i=1; i<=100; i++)

{

result += i;

}

printf("result[1-100] = %ld \n", result );

printf("result[1-250] = %d \n", func(250) );

return 0;

}

三、在Linux环境下使用GCC进行代码编译

LINUX上可用的C编译器是GNU

C编译器,它建立在自由软件基金会编程许可证的基础上,因此可以自由发布。

LINUX

上的GNU

C编译器(GCC)是一个全功能的ANCI

C兼容编译器,而一般UNIX(如SCO

UNIX)用的编译器是CC。下面介绍GCC和一些GCC编译器最常用的选项。

1、使用GCC

通常后跟一些选项和文件名来使用GCC编译器。GCC命令的基本用法如下:

gcc [options] [filenames]

命令行选项指定的编译过程中的具体操作

2、GCC常用选项

GCC有超过100个的编译选项可用,这些选项中的许多可能永远都不会用到,但一些主要的选项将会频繁使用。很多的GCC选项包括一个以上的字符,因此必须为每个选项指定各自的连字符,并且就像大多数LINUX

命令一样不能在一个单独的连字符后跟一组选项。例如,下面的命令是不同的:

gcc -p-g

test.c

gcc -pg

test.c

第一条命令告诉GCC编译test.c时为prof命令建立剖析(profile)信息并且把调试信息加入到可执行文件里。第二条命令告诉GCC只为gprof命令建立剖析信息。

当不用任何选项编译一个程序时,GCC将建立(假定编译成功)一个名为a.out的可执行文件。例如,

gcc

test.c

编译成功后,当前目录下就产生了一个a.out文件。

也可用-o选项来为即将产生的可执行文件指定一个文件名来代替a.out。例如:

gcc –o count

count.c

此时得到的可执行文件就不再是a.out,而是count。

GCC也可以指定编译器处理步骤多少。-c选项告诉GCC仅把源代码编译为目标代码而跳过汇编和连接步骤。这个选项使用得非常频繁因为它编译多个C程序时速度更快且更易于管理。默认时GCC建立的目标代码文件有一个.o的扩展名。

3、执行文件

格式: ./可执行文件名

例:./test

四、在Linux环境下使用GDB进行代码调试

LINUX包含了一个叫gdb的GNU调试程序。gdb是一个用来调试C和C++程序的强有力调试器。它使你能在程序运行时观察程序的内部结构和内存的使用情况。它具有以下一些功能:

•监视程序中变量的值;

设置断点以使程序在指定的代码行上停止执行;

•一行行的执行代码。

以下是利用gdb进行调试的步骤:

1、调试编译代码

为了使gdb正常工作,必须使你的程序在编译时包含调试信息。调试信息里包含你程序里的每个变量的类型和在可执行文件里的地址映射以及源代码的行号。gdb利用这些信息使源代码和机器码相关联。

在编译时用 –g 选项打开调试选项。

2、gdb基本命令

命令描述

file

装入欲调试的可执行文件

kill

终止正在调试的程序

list

列出产生执行文件的源代码部分

next

执行一行源代码但不进入函数内部

step

执行一行源代码并进入函数内部

run

执行当前被调试的程序

quit

终止gdb

watch监视一个变量的值而不管它何时被改变

break

在代码里设置断点,使程序执行到这里时被挂起

make

不退出gdb就可以重新产生可执行文件

shell

不离开gdb就执行Linux

shell 命令

3、应用举例

(1)通过Vim输入Test.c

(2)编译,gcc -g Test.c

–o Test,出错

(3)gdb greet

,出现提示符(gdb),此时可在提示符下输入gdb的命令了,如:

(gdb)run

(gdb)list

(4)退出调试状态,返回系统提示符下,

(gdb)quit

四、进程创建

(1)进程创建

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

#include

main()

{

int

p1,p2;

while((p1=fork())=

=-1);

if(p1=

=0)

printf(“child b

process\n”);

else

{

while((p2=fork())=

=-1);

if(p2=

=0)

printf(“child c

process\n”);

else

{

printf(“main process\n”);}

}

}

(2)双进程创建

编写一段程序,使用系统调用fork()创建两个子进程。显示父进程5次,显示子进程3次。试观察记录屏幕上的显示结果,并分析原因。

双进程

#include

#include

#include

int main()

{

pid_t pid; char *

message;

int n;

printf(“fork program

starting\n”);

pid=fork();

switch(pid)

{

case

-1:

perror(“fork failed”);

exit(1);

case

0:

message = “This is the child”;

n=3;

break;

default:

message = “This is the parent”;

n=5;

break;

}

for (; n>0;

n--)

{

puts(message);

sleep(1);

}

if(pid!=0)

wait(NULL);

exit(0);

}

(3)僵死进程

在双进程程序中,将n=3和n=5相互调换,程序变为僵死进程。僵死进程就是父进程已经结束,而子进程仍然在执行的程序。

#include

#include

#include

int main()

{

pid_t pid;

char *

message;

int n;

printf(“fork program

starting\n”);

pid=fork();

switch(pid)

{

case

-1:

perror(“fork failed”);

exit(1);

case

0:

message = “This is the child”;

n=5;

break;

default:

message = “This is the parent”;

n=3;

break;

}

for (; n>0;

n--)

{

puts(message);

sleep(1);

}

exit(0);

}

利用./fork2 &

然后利用ps –al浏览进程的运行情况。

(4)进程的控制

修改已编写的程序,将每一个进程输出一个字符改为每一个进程输出一句话,在观察程序执行时屏幕上出现的现象,并分析原因。

如果在程序中使用系统调用lockf()来给每一个进程加锁,可以实现进程之间的互斥,观察并分析出现的现象。Lockf(1,1,0)是给输出屏幕加锁,lockf(1,0,0)解锁。

#include

#include

main()

{

int p1,p2,i;

while

((p1=fork())==-1);

if(p1==0)

{

lockf(1,1,0);

for(i=0;i<5;i++)

printf("child1 is

%d\n",i);

lockf(1,0,0);

}

else

{

while((p2=fork())==-1);

if(p2==0)

{

lockf(1,1,0);

for(i=0;i<5;i++)

printf("child2 is

%d\n",i);

lockf(1,0,0);

}

else

{

lockf(1,1,0);

for(i=0;i<5;i++)

printf("child3 is

%d\n",i);

lockf(1,0,0);

}

}

}

(5)使用Pipe管道传输数据

建立一个pipe, 同时父进程生成一个子进程,子进程向pipe

写入一个字符串”Hello world”,父进程从pipe

中读取该字符串。

#include

main()

{

Int x, fd[2];

char buf[30],s[30];

pipe(fd);

while((x=fork())==-1);

if(x==0)

{

sprintf(buf,"Hello World!\n");

write(fd[1],buf,30);

exit(0);

}

else

printf("%s",s);

}

}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值