这学期操作系统课程实践的实验内容,相对比较容易。主要是掌握无名管道的用法和利用信号量实现进程间资源的互斥使用。
题目要求
由父进程创建一个管道,然后再创建3个子进程,并由这三个子进程利用管道与父进程之间进行通信:子进程发送消息,父进程等三个子进程全部发送完消息后再接受消息。通信的具体内容可根据自己的需要随意设计,要求能试验阻塞型读写过程中的各种情况,并能要实现进程间对管道的互斥访问。运行程序,观察各种情况下,进程实际读写的字节数以及进程阻塞唤醒的情况。
要点
管道:管道是一种把两个进程之间的标准输入和标准输出连接起来的机制,从而提供一种让多个进程间通信的方法,当进程创建管道时,每次都需要提供两个文件描述符来操作管道。其中一个对管道进行写操作,另一个对管道进行读操作。对管道的读写与一般的IO系统函数一致,使用write()函数写入数据,使用read()读出数据。
管道分无名管道和有名管道
1. 无名管道主要用于父进程与子进程之间,或者两个兄弟进程之间,通过int pipe(fd[2])创建。fd[0]控制读端,fd[1]控制写端。
2. 命名管道也被称为FIFO文件,是一种特殊类型的文件,它在文件系统中以文件名的形式存在,FIFO代表先进先出。FIFO可以用在非亲缘关系的进程间的通信,而它的真正用途是在服务器和客户端之间。FIFO管道是先调用mkfifo创建,然后再用open打开得到fd来使用。
3. 管道都是半双工的,是一个单向数据流。
进程:一个进程,包括代码、数据和分配给进程的资源。
fork()函数通过系统调用创建一个与原来进程几乎完全相同的进程,也就是两个进程可以做完全相同的事,但如果初始参数或者传入的变量不同,两个进程也可以做不同的事。一个进程调用fork()函数后,系统先给新的进程分配资源,例如存储数据和代码的空间。然后把原来的进程的所有值都复制到新的新进程中,只有少数值与原来的进程的值不同。相当于克隆了一个自己。
fork被调用一次,却能够返回两次,它可能有三种不同的返回值:
1. 在父进程中,fork返回新创建子进程的进程ID;
2. 在子进程中,fork返回0;
3. 如果出现错误,fork返回一个负值;
在fork函数执行完毕后,如果创建新进程成功,则出现两个进程,一个是子进程,一个是父进程。在子进程中,fork函数返回0,在父进程中,fork返回新创建子进程的进程ID。我们可以通过fork返回的值来判断当前进程是子进程还是父进程。
信号量:信号量的使用主要是用来保护共享资源,使得资源在一个时刻只有一个进程(线程)
所拥有。
信号量的值为正的时候,说明它空闲。所测试的线程可以锁定而使用它。若为0,说明
它被占用,测试的线程要进入睡眠队列中,等待被唤醒。
信号量分内核信号量和用户态进程使用的信号量,用户态进程使用的信号量又分POSIX信号量和SYSTEM V信号量。
POSIX信号量又分为有名信号量和无名信号量。有名信号量,其值保存在文件中, 所以它可以用于线程也可以用于进程间的同步,通过sem_t *sem_open(const char *name, int oflag, mode_t mode, unsigned int value);创建;
无名信号量,其值保存在内存中,通过int sem_init(sem_t *sem, int pshared, unsigned int value)创建;。
使用方法可参考:
实现代码:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70#include
#include
#include
#include
#include
#include
#include
#include
#define MAXSIZE 100
int (){
int fd[2],n;
pid_t pid;
char buf[MAXSIZE];
sem_t scanwrite;
sem_init(&scanwrite,0,1);
if(pipe(fd) < 0){
fprintf(stderr, "create Pipe Error %sn", strerror(errno));
exit(EXIT_FAILURE);
}
if((pid = fork()) < 0)
{
fprintf(stderr, "create Fork Error %sn", strerror(errno));
exit(EXIT_FAILURE);
}
if(pid == 0){
close(fd[0]);
sem_wait(&scanwrite);
write(fd[1],"I'm big brother.n",17);
sem_post(&scanwrite);
}
else
{
if((pid = fork()) < 0)
{
fprintf(stderr, "create Fork Error %sn", strerror(errno));
exit(EXIT_FAILURE);
}
if(pid == 0){
close(fd[0]);
sem_wait(&scanwrite);
write(fd[1],"I'm second brother.n",20);
sem_post(&scanwrite);
}
else{
if((pid = fork()) < 0)
{
fprintf(stderr, "create Fork Error %sn", strerror(errno));
exit(EXIT_FAILURE);
}
if(pid == 0){
close(fd[0]);
sem_wait(&scanwrite);
write(fd[1],"I'm last brother.n",18);
sem_post(&scanwrite);
}
else{
wait(0);
wait(0);
wait(0);
close(fd[1]);
n = read(fd[0],buf,MAXSIZE);
printf("%d bytes read:n%s",n,buf);
}
}
}
return 0;
}
shell输入指令1
2$ gcc communication.c -o com -lpthread
$ ./com
运行结果:1
2
3
455 bytes read:
I'm big brother.
I'm second brother.
I'm last brother.
更多推荐