目录
第1关:信号量IPC操作考查
任务描述
本关任务:编写小程序使用信号量实现进程间通信,理解信号量是主要用来实现进程间同步,避免并发访问共享资源。
相关知识
为了完成本关任务,你需要掌握:信号量的相关通信过程。
基于信号量的进程间通信
1)信号量集合数据结构 规定了信号量的权限、指针、最近修改时间和队列中信号量的队列信息。
2) 单信号量结构
struct sem { int semval;//信号量的值 int sempid;//最近一个操作的进程号PID }
3)创建信号量集合
int semget(key_t key,int _nsems,int _semflg) key 由ftok创建 nsems为创建的信号量个数,以数组方式存储 semflg标识信号量集合的权限,最终权限属于当前进程 umask值与设置的perm值,即perm&~umask,也可以如下: IPC_CREAT:如果key不存在,创建 IPC_EXCL:如果key存在,返回失败 IPC_NOWAIT:如果需要等待返回失败
4)控制信号量集合、信号量
semctl(int semid,int semnum,int cmd,...); semid要操作的信号量集合 semnum集合中信号量的编号 cmd执行的操作 ipc头文件中 IPC_RMID删除 IPC_SET设置ipc_perm参数 IPC_STAT获取ipc_perm参数 IPC_INFO获取系统信息
自定义
#define GETPID 获取信号量拥有者的pid #define GETVAL 获取信号量的值返回信号的值 #define GETALL 获取所有信号量的值 #define GETNCNT 获取等待信号量的值递增的进程数 #define GETZCNT获取等待信号量的值递减的进程数 #define SETVAL 设置信号量的值,设置值在第四个参数中 #define SETALL 设置所有信号量的值
编程要求
根据提示,在右侧编辑器补充代码,了解OpenEuler系统如何使用信号量进行IPC通信,代码中先用sem_read_array[]数组存储数据,并进行信号量与数据的输出,我们需要补充代码使用semctl函数输出一样的数据。
答案:
#include <errno.h> #define MAX_SEMAPHORES 5 #include <stdio.h> #include <sys/types.h> #include <sys/sem.h> #include <errno.h> #define MAX_SEMAPHORES 5 int main(int argc,char *argv[]) { int i, ret, semid; unsigned short sem_array[MAX_SEMAPHORES]; unsigned short sem_read_array[MAX_SEMAPHORES]; union semun { int val; struct semid_ds *buf; unsigned short *array; } arg; semid = semget( IPC_PRIVATE, MAX_SEMAPHORES,IPC_CREAT | 0666 ); if (semid != -1) { for ( i = 0 ; i < MAX_SEMAPHORES ; i++ ) { sem_array[i] = (unsigned short)(i+1); } arg.array = sem_array; ret = semctl( semid, 0, SETALL, arg); if (ret == -1) printf("SETALL failed (%d)\n", errno); arg.array = sem_read_array; ret = semctl( semid, 0, GETALL, arg ); if (ret == -1) printf("GETALL failed (%d)\n", errno); for ( i = 0 ; i < MAX_SEMAPHORES ; i++ ) { printf("Semaphore %d, value %d\n", i, sem_read_array[i] ); } for ( i = 0 ; i < MAX_SEMAPHORES ; i++ ) { /*请调用semctl函数,读取并输出与上述数组输出相同的输出*/ ret = semctl(semid, i, GETVAL); if (ret == -1) { printf("GETVAL failed for semaphore %d (%d)\n", i, errno); } else { printf("Semaphore %d, value %d\n", i, ret); } } ret = semctl( semid, 0, IPC_RMID ); } else printf("Could not allocate semaphore (%d)\n", errno); return 0; }
第1关:命名管道与信号IPC操作考查
任务描述
本关任务:编写小程序,先创建命名管道,子进程以读的方式打开,父进程以写的方式打开,查看相关输出。
相关知识
为了完成本关任务,你需要掌握:命名管道的的相关通信过程。
命名管道通信过程
无名管道是临时的,完成通信就自动消失。
1)必须同时有读和写操作,可以是一个或者多个进程
2)无数据,读堵塞 有数据,小于预读取量,读出所有。 有数据,大于预读取量,读出期望数量。
3)无空间,写堵塞 有空间,小于欲写入量,写满阻塞。 有空间,大于欲写入量,写完返回。 4)中途一个退出操作 写退出,返回SIGPIPE信号。 读退出,读操作不阻塞,直接返回0。
编程思路
根据提示,在右侧编辑器补充代码,使用SIGPIPE信号进行记录,读通道关闭后写通道写入。首先子进程以读的方式打开管道,然后父进程以写的方式打开管道,父进程当即睡眠1秒,子进程关闭读管道,当父进程休眠完成后开始写入,会发出写入失败信号。
答案:
#include<stdio.h> #include<string.h> #include<fcntl.h> #include<signal.h> #include<sys/types.h> void handler(int sig) { printf("sig=%d\n",sig); } int main(void) { int j; signal(SIGPIPE,handler);//在reader中止之后写Pipe的时候发送 unlink("FIFO"); mkfifo("FIFO",0644); pid_t pid; pid=fork(); if (pid == 0) { /*子进程打开读管道,随后关闭管道*/ int fd = open("FIFO", O_RDONLY); close(fd); } else { /*父进程打开写通道,休眠1秒,尝试写入*/ int fd = open("FIFO", O_WRONLY); sleep(1); char buffer[] = "Hello, pipe!"; int ret = write(fd, buffer, strlen(buffer)); close(fd); } }