设计一 进程管理
一、实验目的
1. 理解Linux 系统中进程通信的基本原理。
2. 加深对进程概念的理解,明确进程与程序的区别。
3. 掌握fork()、fockf()、pipe(fd)等函数的用法。
二、实验预备知识
1.fork()函数
头文件: #include <unistd.h>
函数定义: int fork( void );
返回值: 子进程中返回0,父进程中返回子进程ID,出错返回-1
函数说明:
一个现有进程可以调用fork函数创建一个新进程。由fork创建的新进程被称为子进程(child process)。fork函数被调用一次但返回两次。两次返回的唯一区别是子进程中返回0值而父进程中返回子进程ID。
子进程是父进程的副本,它将获得父进程数据空间、堆、栈等资源的副本。注意,子进程持有的是上述存储空间的“副本”,这意味着父子进程间不共享这些存储空间,它们之间共享的存储空间只有代码段。
示例代码:
#include <unistd.h>
#include <stdio.h>
int main(int argc, char ** argv )
{
int pid = fork();
if(pid == -1 )
{
printf("error!");
}
else if( pid == 0 )
{
printf("This is the child process!");
}
else
{
printf("This is the parent process! child process id = %d", pid);
}
return 0;
}
Fork()系统在Linux中的返回值是没有NULL的.
Error Codes 出错返回错误信息如下:
EAGAIN 达到进程数上限.
ENOMEM 没有足够空间给一个新进程分配.
---------------------------------
2. wait() 函数
wait() 函数是用于使父进程(也就是调用 wait() 的进程)阻塞,直到一个子进程结束或者该进程接到了一个指定的信号为止。如果该父进程没有子进程或者他的子进程已经结束,则 wait() 就会立即返回。
3.lockf()函数
对指定文件的指定区域(由size指示)进行加锁或解锁,以实现进程的同步与互斥。其中:
fd是文件描述字;
mode是锁定方式,=1表示加锁,=0表示解锁;
size是指文件fd的指定区域,用0表示从前位置到文件尾。
4.pipe(fd)函数
建立进程间的管道,用于进程通信。格式为:
int fd[2];
pipe(fd);
其中,fd[0]是读端,从管道中读出;fd[1]是写端,向管道中写入。本质上将其当作文件处理。
进程间可通过管道,用write与read来传递数据,但write与read不可以同时进行,在管道中只能有4096字节的数据被缓冲。例:
read(fd[0],buf,size); //从管道出口fd[0]读出size字符的消息置入buf中。
write(fd[1],buf,size); //把buf中的长度为size字符的消息送入管道入口放到fd[1]
5.sleep(second)函数
用于进程的同步与互斥,自变量是暂停秒数。
6.exit(int status)函数
进程结束时调用的函数,在main()函数中调用return,最终也是调用exit()函数。在正常终止时,exit()函数返回进程结束状态status。
exit的执行过程是:
(1)调用atexit或on_exit中注册了的函数,来执行用户定义的操作
(2)关闭流,清除tmpfile创建的临时文件,输出缓冲区记录(如stdout)
(3)执行_exit函数
三、实验代码:
//process_1.c
#include<sys/types.h>
#include<unistd.h>
#include<stdio.h>
#include<sys/wait.h>
#include<stdlib.h>
int main()
{
pid_t pid;
char *message;
int n;
int exit_code;
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;
exit_code = 37;
break;
default:
message = "This is the parent";
n = 3;
exit_code = 0;
break;
}
for(; n > 0 ; n--)
{
puts(message);
sleep(1);
}
if(pid != 0)
{
int stat_val;
pid_t child_pid;
child_pid = wait(&stat_val);
printf("Child has finished:PID = %d/n",child_pid);
if(WIFEXITED(stat_val))
//如果子进程正常结束,它就去一个非零值
{
printf("Child exited with code %d/n",WEXITSTATUS(stat_val));
}
else
{
printf("Child terminated abnormally/n");
}
}
exit(exit_code);
}
//process_2.c
#include<unistd.h>
#include<signal.h>
#include<stdio.h>
#include<stdlib.h>
int pid1,pid2;
int main()
{
int fd[2];
char OutPipe[100],InPipe[100];
pipe(fd); //创建管道
while((pid1 = fork()) == -1);
//创建子进程1并向管道中写入数据
if(pid1 == 0)
{
lockf(fd[1],1,0);
sprintf(OutPipe,"/n Child process 1 is sending message!/n");
write(fd[1],OutPipe,50);
sleep(5);
lockf(fd[1],0,0);
exit(0);
}
else
{
while((pid2 = fork()) == -1);
if(pid2 == 0)
{
lockf(fd[1],1,0);
sprintf(OutPipe,"/n Child process 2 is sending message!/n");
write(fd[1],OutPipe,50);
sleep(5);
lockf(fd[1],0,0);
exit(0);
}
else
{
//读出进程1写入管道中的信息
wait(0);
read(fd[0], InPipe, 50);
printf("%s/n", InPipe);
//读出进程2写入管道中的信息
wait(0);
read(fd[0], InPipe, 50);
printf("%s/n", InPipe);
exit(0);
}
}
}