一:题目介绍
1)实现一个模拟的shell
编写三个不同的程序cmd1.c、cmd2.c 及 cmd3.c,每个程序的功能自定,分别编译成可执行文件cmd1、cmd2 及 cmd3。然后再编写一个程序,模拟shell程序的功能:能根据用户输入的字符串(表示相应的命令名),为相应的命令创建子进程并让它去执行相应的程序,而父进程则等待子进程结束,然后再等待接收下一条命令。如果接收到的命令为exit,则父进程结束,退出模拟shell:如果接收到的命令是无效命令,则显示“Command not found",继续等待输入下一条命令。
2) 由父进程创建一个管道,然后再创建三个子进程,并由这三个子进程利用管道与父进程之间进行通信:子进程发送信息,父进程等三个子进程全部发完消息后再接收信息。通信的具体内容可根据自己的需要随意设计,要求能试验阻塞型读写过程中的各种情况,测试管道的默认大小,并且要求利用 POSIX 信号量机制实现进程间对管道的互斥访问。运行程序,观察各种情况下,进程实际读写的字节数以及进程阻塞唤醒的情况。
3)编写程序创建三个线程:sender1线程、sender2线程和receiver线程,三个线程的功能描述如下:
①sender1线程:运行函数sender1(),它创建一个消息队列,然后等待用户通过终端输入一串字符,并将这串字符通过消息队列发送给receiver线程;可循环发送多个消息,直到用户输入“exit”为止,表示它不再发送消息,最后向receiver线程发送消息“end1”,并且等待receiver的应答,等到应答消息后,将接收到的应答信息显示在终端屏幕上,结束线程的运行。
②sender2线程:运行函数sender2(),共享sender1创建的消息队列,等待用户通过终端输入一串字符,并将这串字符通过消息队列发送给receiver线程可循环发送多个消息,直到用户输入“exit”为止,表示它不再发送消息,最后向receiver线程发送消息“end2”,并且等待receiver的应答,等到应答消息后,将接收到的应答信息显示在终端屏幕上,结束线程的运行。
③receiver线程:运行函数receive(),它通过消息队列接收来自sender1和sender2两个线程的消息,将消息显示在终端屏幕上,当收到内容为“end1”的消息时,就向sender1发送一个应答消息“over1”;当收到内容为“end2”的消息时,就向sender2发送一个应答消息“over2”;消息接收完成后删除消息队列,结束线程的运行。选择合适的信号量机制实现三个线程之间的同步与互斥。
4)利用Linux的共享内存通信机制实现两个进程间的通信
编写程序 sender,它创建一个共享内存,然后等待用户通过终端输入一串字符,并将这串字符通过共享内存发送给receiver;最后,它等待receiver的应答,收到应答消息后,将接收到的应答信息显示在终端屏幕上,删除共享内存,结束程序的运行。编写 receiver程序,它通过共享内存接收来自sender的消息,将消息显示在终端屏幕上,然后再通过该共享内存向sender发送一个应答消息“over”,结束程序的运行。选择合适的信号量机制实现两个进程对共享内存的互斥及同步使用。
二:实验思路
1)
while循环等待命令输入,输入后先判断是否为exit,再创建子进程,判断当前运行在父进程还是子进程上,然后进行相应操作
2)
图2. 程序流程
整个流程主要流程是创建信号量、创建管道、创建子进程、子进程互斥写入管道、父进程读取管道。实验中用到的信号量为mutex、receive1/2/3,其中mutex用于实现管道的互斥访问,receive1/2/3分别是三个写入完毕后用于向父进程发送消息的信号量。使用信号量前需要先删除可能存在的同名信号量再创建,程序结束后关闭并删除。创建管道的过程需要根据pipe的返回值判断是否成功。创建三个子进程的关键在于要让进程之间彼此独立,按照创建次序写入,使用循环较为方便,同时写入管道的内容可以由用户终端输入来指定。实现进程对管道的互斥访问需要注意信号量的使用位置,确保以父进程的读操作只有在所有子进程结束后才读。
3)
图5:总流程图
三个线程:两个发送线程 send_thread_1和send_thread_2,一个接收线程 recv_thread
四个信号量:
send_psx:控制发送线程对消息队列的访问权限。在 send_thread_1 和 send_thread_2 中,通过 sem_wait(&send_psx) 获取发送权限,通过 sem_post(&send_psx) 释放发送权限
recv_psx