You are on page 1of 22

实验三 进程同步与管理

一、实验名称
进程同步与管理
二、实验目的
1.掌握进程的同步概念,明确进程互斥的含义;
2.认识并了解并发执行的实质;
3.掌握生产者和消费者问题;
4.掌握信号实现进程同步的基本方法;
5.掌握信号量机制及其应用。
三、基础知识
1.进程同步及互斥的概念;
2.道实现进程同步的基本方法。
四、实验准备
1.熟悉Linux下PV原语函数的用法;
2.熟悉Linux互斥函数的用法;
3.熟悉P函数放反位置的后果;
4.系统调用fork和lockf的使用;
5.了解signal函数和wait函数的用法;
6.了解管道函数pipe的用法。
五、实验要求
实验程序截图,截图请包含学号和姓名。对本实验的程序名依次编号。
六、实验内容
1.多个⽣产者进程和多个消费者进程共享⼀个初始为空、固定⼤⼩为 n 的缓存(缓冲区),
用 PV 原语模拟实现。
【问题描述】⽣产者的⼯作是制造数据,只有缓冲区没满时,⽣产者才能把消息放⼊到缓冲
区,否则必须等待; 同时,只有缓冲区不空时,消费者才能从中取出消息,⼀次消费⼀段
数据(即将其从缓存中移出),否则必须等待。由于缓冲区是临界资源,它只允许⼀个⽣
产者放⼊消息,或者⼀个消费者从中取出消息,同时只允许⼀个⽣产者进⾏制造,多个⽣
产者不能同时制造,也只允许⼀个消费之进⾏消费,多个消费者不能同时进⾏消费。
当缓冲为空的时候,消费者不能消费,必须等待。当缓存为满的时候,⽣产者不能⽣
产,必须等待。⽣产者消费者之间必须互斥
【实验思路】
(1)设置三个信号量:empty (以记录有多少空位)、full (以记录有多少满位)以及
mutex
(⼆进制信号量或互斥信号量,以保护对缓冲插⼊与删除的操作)
(2)当信号量empty为0的时候,此时有限缓存已满,⽣产者必须等待,当信号量full
为0的时候,此时有限缓存为空,消费者⽆法进⾏消费,必须等待
(3)信号量mutex使得各个线程之间互斥,每次只允许⼀个线程进⼊临界区,⼀旦有
线程进⼊⾃⼰的临界区,其余线程必须等待
(4)有限缓存区为循环队列,尾部插⼊新的产品,头部产品先被消耗

2.请使用共享内存段和信号量实现“读者-写者问题”

3.有一个阅览室,共有 100 个座位,读者进入时必须先在一张登记表上登记,该表为每一


座位列一表目,包括座号和读者姓名等,读者离开时要消掉登记的信息,试问:
(1)为描述读者的动作,应编写几个程序,设置几个进程?
(2)试用 PV 操作描述读者进程之间的同步关系。学号_lab3_5.c
4.请使用信号量仿真模拟“哲学家就餐问题”

5.请百度 lockf(1,1,0)和 lock(1,0,0)函数的用法和用途。(选做)


6.写出 Linux 下 C 编程,建立管道。(选做)
附件 1 生产者消费 c 程序
# include <stdio.h>
# include <stdlib.h>
# include <time.h>
# include <sys/types.h>
# include <pthread.h>
# include <semaphore.h>
# include <string.h>
# include <unistd.h>
#define BUFFER_SIZE 5
typedef int buffer_item;
//semaphores
sem_t empty, full, mutex;
//buffer
buffer_item buffer[BUFFER_SIZE];
int in, out;
//存储数据的结构体
struct data {
int id;
int opTime;
int lastTime;
int productId;
};
};
//有限缓存插⼊--⽣产
int insert_item(buffer_item item) {
/* insert item into buffer */
buffer[out] = item;
out = (out + 1) % BUFFER_SIZE;
return 0;
}
//有限缓存删除--消费
int remove_item(buffer_item *item) {
/* remove an object from buffer and then place it in item */
*item = buffer[in];
in = (in + 1) % BUFFER_SIZE;
return 0;
}
//⽣产者
void *producer(void* param) {
int productId = ((struct data*)param)->productId;
int lastTime = ((struct data*)param)->lastTime;
int opTime = ((struct data*)param)->opTime;
int id = ((struct data*)param)->id;
free(param);
sleep(opTime);
sem_wait(&empty);
sem_wait(&mutex);
/* critical section */
//add a item
insert_item(productId);
sleep(lastTime);
printf("Thread %d: Producer produce %d\n", id, productId);
sem_post(&mutex);
sem_post(&full);
pthread_exit(0);
}
//消费者
void *consumer(void* param) {
int lastTime = ((struct data*)param)->lastTime;
int opTime = ((struct data*)param)->opTime;
int id = ((struct data*)param)->id;
free(param);
sleep(opTime);
sem_wait(&full);
sem_wait(&mutex);
/* critical section */
//remove a item
buffer_item item;
remove_item(&item);
sleep(lastTime);
printf("Thread %d: Consumer consume %d\n", id, item);
sem_post(&mutex);
sem_post(&empty);
pthread_exit(0);
}
int main() {
//pthread
pthread_t tid; // the thread identifier
pthread_attr_t attr; //set of thread attributes
/* get the default attributes */
pthread_attr_init(&attr);
//initial the semaphores
sem_init(&mutex, 0, 1);
sem_init(&empty, 0, BUFFER_SIZE);
sem_init(&full, 0, 0);
in = out = 0;
int id = 0;
while(scanf("%d", &id) != EOF) {
char role; //producer or consumer
int opTime; //operating time
int lastTime; //run time
int productId; //product id
scanf("%c%d%d", &role, &opTime, &lastTime);
struct data* d = (struct data*)malloc(sizeof(struct data));
d->id = id;
d->opTime = opTime;
d->lastTime = lastTime;
if(role == 'P') {
scanf("%d", &productId);
d->productId = productId;
pthread_create(&tid, &attr, producer, d);
}
else if(role == 'C')
pthread_create(&tid, &attr, consumer, d);
}
//释放信号量
sem_destroy(&mutex);
sem_destroy(&empty);
sem_destroy(&full);
return 0;
}
测试数据:
1C35
2P451
3C52
4C65
5P732
6P843

输出结果
附件 4:哲学家就餐算法的 java 实现
操作系统平台:Windows 2007
开发平台:eclipse
程序语言:Java
设计思想:定义五个类,分别为哲学家 A、哲学家 B、哲学家 C、哲学家 D、哲学家 E。五个类均
有 thinking(思考)和 Eating(吃饭)两个方法。当选定哪几位哲学家就餐后,使用单线程处
理选定的哲学家就餐顺序,如果 A 要就餐,询问 C 是否要就餐,否则询问 D 是否要就餐,
否则 A 自己就餐;然后 B 进行就餐,如果 B 就餐,询问 D 是否要就餐,否则询问 E 是否要就
餐,否则 B 就餐;然后 C 进行就餐,如果 C 就餐,询问 E 是否就餐,否则 C 就餐;最后 D 就
餐,再 E 就餐。
数据结构的说明
采用链式 timer(计时器),每当一个 timer 结束时,链接到下一个 timer 中去,实现多
步哲学家就餐顺序,当最后一个哲学家就餐完成后弹出信息面板提示就餐完成。
调用关系:ShowPannel 为主类,StateControl 为哲学家类,showPannel 在 timer 中调
用哲学家类实现就餐、思考的转换和选择。
各模块的算法流程图

StateControl 类:定义哲学家类

Thinking:setText(空闲);

Eating:setText(正在使用);

showPannel 类:点击确定后选定哲学家就餐

设计思想:定义五个类,分别为哲学家 A、哲学家 B、哲学家 C、哲学家 D、哲学家 E。五个


类均有 thinking(思考)和 Eating(吃饭)两个方法。当选定哪几位哲学家就餐后,使用单线
程处理选定的哲学家就餐顺序,如果 A 要就餐,询问 C 是否要就餐,否则询问 D 是否要就
餐,否则 A 自己就餐;然后 B 进行就餐,如果 B 就餐,询问 D 是否要就餐,否则询问 E 是否
要就餐,否则 B 就餐;然后 C 进行就餐,如果 C 就餐,询问 E 是否就餐,否则 C 就餐;最后
D 就餐,再 E 就餐。

A 组:AC 就餐 AD 就餐 A 就餐

B 组:BD 就餐 BE 就餐 B 就餐

C 组:CE 就餐 C 就餐

D 组:D 就餐

E 组:E 就餐

StateControl 类:
package philosopher;
class philosopherA{
void Thinking(){//正在思考时不占用筷子资源
ShowPannel.chops1.setText("筷子1当前状态:空闲");
ShowPannel.chops2.setText("筷子2当前状态:空闲");
}
void Eating(){//吃时两个筷子状态为1,即正在使用
ShowPannel.chops1.setText("筷子1当前状态:正在使用");
ShowPannel.chops2.setText("筷子2当前状态:正在使用");
}
}

class philosopherB{
void Thinking(){//正在思考时不占用筷子资源
ShowPannel.chops2.setText("筷子2当前状态:空闲");
ShowPannel.chops3.setText("筷子3当前状态:空闲");
}
void Eating(){//吃时两个筷子状态为1,即正在使用
ShowPannel.chops2.setText("筷子2当前状态:正在使用");
ShowPannel.chops3.setText("筷子3当前状态:正在使用");
}
}

class philosopherC{
void Thinking(){//正在思考时不占用筷子资源
ShowPannel.chops3.setText("筷子3当前状态:空闲");
ShowPannel.chops4.setText("筷子4当前状态:空闲");
}
void Eating(){//吃时两个筷子状态为1,即正在使用
ShowPannel.chops3.setText("筷子3当前状态:正在使用");
ShowPannel.chops4.setText("筷子4当前状态:正在使用");
}
}

class philosopherD{
void Thinking(){//正在思考时不占用筷子资源
ShowPannel.chops4.setText("筷子4当前状态:空闲");
ShowPannel.chops5.setText("筷子5当前状态:空闲");
}
void Eating(){//吃时两个筷子状态为1,即正在使用
ShowPannel.chops4.setText("筷子4当前状态:正在使用");
ShowPannel.chops5.setText("筷子5当前状态:正在使用");
}
}
class philosopherE{
void Thinking(){//正在思考时不占用筷子资源
ShowPannel.chops5.setText("筷子5当前状态:空闲");
ShowPannel.chops1.setText("筷子1当前状态:空闲");
}
void Eating(){//吃时两个筷子状态为1,即正在使用
ShowPannel.chops5.setText("筷子5当前状态:正在使用");
ShowPannel.chops1.setText("筷子1当前状态:正在使用");
}
}
ShowPannel 类:
package philosopher;
import java.awt.Checkbox;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import java.awt.event.ActionListener;
public class ShowPannel extends JFrame implements ChangeListener,ActionListener{
private static final long serialVersionUID = 1L;
public JFrame frame = null;
public static ShowPannel spPannel;
public static JButton selectButton;//选择就餐的哲学家
public static JLabel chops1,chops2,chops3,chops4,chops5;
public static JProgressBar
progressBar1,progressBar2,progressBar3,progressBar4,progressBar5;
public static Timer timer1,timer2,timer3,timer4,timer5;
philosopherA phiA;//五位哲学家
philosopherB phiB;
philosopherC phiC;
philosopherD phiD;
philosopherE phiE;
public static boolean[] philosopher = {false,false,false,false,false};//五个哲学家状态
public static int[] Mark = {0,0,0,0,0,0,0,0,0,0};//标记就餐组合
JLabel Label1;
JLabel senseJLabel1,senseJLabel2,senseJLabel3,senseJLabel4;//横杠
JLabel blank1,blank2,blank3,blank4;
JLabel state;//当前状态
Checkbox phi1,phi2,phi3,phi4,phi5;//五位哲学家选择

public static void main(String[] args) {


spPannel = new ShowPannel();
}
public ShowPannel(){
Label1 = new JLabel("选择就餐的哲学家:");
state = new JLabel("资源使用状态");
senseJLabel1 = new JLabel("—————————————————");
senseJLabel2 = new JLabel("—————————————————");
senseJLabel3 = new JLabel("—————————————————");
senseJLabel4 = new JLabel("————————————————");
blank1 = new JLabel(" ");//废块
blank2 = new JLabel(" ");
blank3 = new JLabel(" ");
blank4 = new JLabel(" ");

chops1 = new JLabel("筷子1当前状态:空闲");


chops2 = new JLabel("筷子2当前状态:空闲");
chops3 = new JLabel("筷子3当前状态:空闲");
chops4 = new JLabel("筷子4当前状态:空闲");
chops5 = new JLabel("筷子5当前状态:空闲");
phiA = new philosopherA();
phiB = new philosopherB();
phiC = new philosopherC();
phiD = new philosopherD();
phiE = new philosopherE();
//checkBox哲学家复选框
phi1 = new Checkbox("哲学家A",null,false);
phi2 = new Checkbox("哲学家B",null,false);
phi3 = new Checkbox("哲学家C",null,false);
phi4 = new Checkbox("哲学家D",null,false);
phi5 = new Checkbox("哲学家E",null,false);
selectButton = new JButton("就餐");
selectButton.addActionListener(this);
//进度条设置
progressBar1 = new JProgressBar(0,100);
progressBar2 = new JProgressBar(0,100);
progressBar3 = new JProgressBar(0,100);
progressBar4 = new JProgressBar(0,100);
progressBar5 = new JProgressBar(0,100);
progressBar1.setValue(0);
progressBar2.setValue(0);
progressBar3.setValue(0);
progressBar4.setValue(0);
progressBar5.setValue(0);
progressBar1.setStringPainted(true);
progressBar2.setStringPainted(true);
progressBar3.setStringPainted(true);
progressBar4.setStringPainted(true);
progressBar5.setStringPainted(true);

timer1 = new Timer(20, this); //10个计时器


timer2 = new Timer(20, this);
timer3 = new Timer(20, this);
timer4 = new Timer(20, this);
timer5 = new Timer(20, this);

frame = new JFrame("哲学家就餐问题");


frame.setLayout(new FlowLayout(FlowLayout.LEFT,20,30));
frame.add(Label1);
frame.add(phi1); frame.add(phi2); frame.add(phi3);
frame.add(phi4); frame.add(phi5);
//资源使用状况
frame.add(senseJLabel1); frame.add(selectButton); frame.add(senseJLabel3);
frame.add(senseJLabel2); frame.add(state); frame.add(senseJLabel4);
//筷子块
frame.add(chops1); frame.add(progressBar1); frame.add(blank1);
frame.add(chops2); frame.add(progressBar2); frame.add(blank2);
frame.add(chops3); frame.add(progressBar3); frame.add(blank3);
frame.add(chops4); frame.add(progressBar4); frame.add(blank4);
frame.add(chops5); frame.add(progressBar5);
frame.setLocationRelativeTo(null);
frame.setSize(600,500);
frame.setResizable(false);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setVisible(true);
}
@Override
public void actionPerformed(ActionEvent e) {
if(e.getSource()==selectButton){
philosopher[0] = phi1.getState();//获取5个哲学家一轮就餐顺序
philosopher[1] = phi2.getState();
philosopher[2] = phi3.getState();
philosopher[3] = phi4.getState();
philosopher[4] = phi5.getState();

selectButton.setText("就餐中...");
if(philosopher[0] == true){
if(philosopher[2] == true){
//哲学家AC一起吃饭
Mark[0] = 1;
philosopher[2] = false;
}else if(philosopher[3] == true){
//哲学家AD一起吃饭
Mark[1] = 1;
philosopher[3] = false;
}else{
//哲学家A要吃饭
Mark[2] = 1;
philosopher[0] = false;
}
}
if(philosopher[1] == true){
if(philosopher[3] == true){
//哲学家BD一起吃饭
Mark[3] = 1;
philosopher[3] = false;
}else if(philosopher[4] == true){
//哲学家BE一起吃饭
Mark[4] = 1;
philosopher[4] = false;
}else{
//哲学家B要吃饭
Mark[5] = 1;
philosopher[1] = false;
}
}
if(philosopher[2] == true){
if(philosopher[4] == true){
//哲学家CE一起吃饭
Mark[6] = 1;
philosopher[4] = false;
}
else{
//哲学家C吃饭
Mark[7] = 1;
philosopher[2] = false;
}
}
if(philosopher[3] == true){
//哲学家D吃饭
Mark[8] = 1;
philosopher[3] = false;
}
if(philosopher[4] == true){
//哲学家E吃饭
Mark[9] = 1;
philosopher[4] = false;
}
timer1.start();
}
if (e.getSource() == timer1) {
if(Mark[0] == 1){//判断AC是否就餐,是则执行AC就餐后执行timer2,否则直接执
行timer2
int value1 = progressBar1.getValue();
int value2 = progressBar2.getValue();
int value3 = progressBar3.getValue();
int value4 = progressBar4.getValue();
if(value1 < 100){
value1++;
value2++;
value3++;
value4++;
if(value1 == 1){
phiA.Eating();
phiC.Eating();
}
progressBar1.setValue(value1);
progressBar2.setValue(value2);
progressBar3.setValue(value3);
progressBar4.setValue(value4);
if(value1 == 100){
phiA.Thinking();
phiC.Thinking();
progressBar1.setValue(0);
progressBar2.setValue(0);
progressBar3.setValue(0);
progressBar4.setValue(0);
Mark[0] = 0;//重置标记值
timer1.stop();
timer2.start();
}
}
}else if(Mark[1] == 1){//判断是否AD就餐,是则饭后执行timer2,否则直接执行
int value1 = progressBar1.getValue();
int value2 = progressBar2.getValue();
int value4 = progressBar4.getValue();
int value5 = progressBar5.getValue();
if(value1 < 100){
value1++;
value2++;
value4++;
value5++;
if(value1 == 1){
phiA.Eating();
phiD.Eating();
}
progressBar1.setValue(value1);
progressBar2.setValue(value2);
progressBar4.setValue(value4);
progressBar5.setValue(value5);
if(value1 == 100){
phiA.Thinking();
phiD.Thinking();
progressBar1.setValue(0);
progressBar2.setValue(0);
progressBar4.setValue(0);
progressBar5.setValue(0);
Mark[1] = 0;//重置标记值
timer1.stop();
timer2.start();
}
}
}else if(Mark[2] == 1){//判断A是否就餐,是则饭后执行timer2,否则直接执行
int value1 = progressBar1.getValue();
int value2 = progressBar2.getValue();
if(value1 < 100){
value1++;
value2++;
if(value1 == 1){
phiA.Eating();
}
progressBar1.setValue(value1);
progressBar2.setValue(value2);
if(value1 == 100){
phiA.Thinking();
progressBar1.setValue(0);
progressBar2.setValue(0);
Mark[2] = 0;//重置标记值
timer1.stop();
timer2.start();
}
}
}else{
timer1.stop();
timer2.start();
}
}
if(e.getSource() == timer2){//判断BD就餐,如果是则饭后执行timer3
if(Mark[3] == 1){
int value2 = progressBar2.getValue();
int value3 = progressBar3.getValue();
int value4 = progressBar4.getValue();
int value5 = progressBar5.getValue();
if(value2 < 100){
value2++;
value3++;
value4++;
value5++;
if(value2 == 1){
phiB.Eating();
phiD.Eating();
}
progressBar2.setValue(value2);
progressBar3.setValue(value3);
progressBar4.setValue(value4);
progressBar5.setValue(value5);
if(value2 == 100){
phiB.Thinking();
phiD.Thinking();
progressBar2.setValue(0);
progressBar3.setValue(0);
progressBar4.setValue(0);
progressBar5.setValue(0);
Mark[3] = 0;//重置标记值
timer2.stop();
timer3.start();
}
}
}else if(Mark[4] == 1){//判断BE是否就餐,是则饭后执行timer3
int value2 = progressBar2.getValue();
int value3 = progressBar3.getValue();
int value5 = progressBar5.getValue();
int value1 = progressBar1.getValue();
if(value2 < 100){
value2++;
value3++;
value5++;
value1++;
if(value2 == 1){
phiB.Eating();
phiE.Eating();
}
progressBar2.setValue(value2);
progressBar3.setValue(value3);
progressBar5.setValue(value5);
progressBar1.setValue(value1);
if(value2 == 100){
phiB.Thinking();
phiE.Thinking();
progressBar2.setValue(0);
progressBar3.setValue(0);
progressBar5.setValue(0);
progressBar1.setValue(0);
Mark[4] = 0;//重置标记值
timer2.stop();
timer3.start();
}
}
}else if(Mark[5] == 1){//判断B是否就餐
int value2 = progressBar2.getValue();
int value3 = progressBar3.getValue();
if(value2 < 100){
value2++;
value3++;
if(value2 == 1){
phiB.Eating();
}
progressBar2.setValue(value2);
progressBar3.setValue(value3);
if(value2 == 100){
phiB.Thinking();
progressBar2.setValue(0);
progressBar3.setValue(0);
Mark[5] = 0;//重置标记值
timer2.stop();
timer3.start();
}
}
}else{
timer2.stop();
timer3.start();
}
}
if(e.getSource() == timer3){
if(Mark[6] == 1){//判断CE是否就餐,是则饭后执行timer4
int value3 = progressBar3.getValue();
int value4 = progressBar4.getValue();
int value5 = progressBar5.getValue();
int value1 = progressBar1.getValue();
if(value3 < 100){
value3++;
value4++;
value5++;
value1++;
if(value3 == 1){
phiC.Eating();
phiE.Eating();
}
progressBar3.setValue(value4);
progressBar4.setValue(value3);
progressBar5.setValue(value5);
progressBar1.setValue(value1);
if(value3 == 100){
phiC.Thinking();
phiE.Thinking();
progressBar3.setValue(0);
progressBar4.setValue(0);
progressBar5.setValue(0);
progressBar1.setValue(0);
Mark[6] = 0;//重置标记值
timer3.stop();
timer4.start();
}
}
}else if(Mark[7] == 1){//判断B是否就餐
int value3 = progressBar3.getValue();
int value4 = progressBar4.getValue();
if(value3 < 100){
value3++;
value4++;
if(value3 == 1){
phiC.Eating();
}
progressBar3.setValue(value3);
progressBar4.setValue(value4);
if(value3 == 100){
phiC.Thinking();
progressBar3.setValue(0);
progressBar4.setValue(0);
Mark[7] = 0;//重置标记值
timer3.stop();
timer4.start();
}
}
}else{
timer3.stop();
timer4.start();
}
}
if(e.getSource() == timer4){
if(Mark[8] == 1){//判断D是否就餐
int value4 = progressBar4.getValue();
int value5 = progressBar5.getValue();
if(value4 < 100){
value4++;
value5++;
if(value4 == 1){
phiD.Eating();
}
progressBar4.setValue(value4);
progressBar5.setValue(value5);
if(value4 == 100){
phiD.Thinking();
progressBar4.setValue(0);
progressBar5.setValue(0);
Mark[8] = 0;//重置标记值
timer4.stop();
timer5.start();
}
}
}else{
timer4.stop();
timer5.start();
}
}
if(e.getSource() == timer5){
if(Mark[9] == 1){//判断E是否就餐
int value5 = progressBar5.getValue();
int value1 = progressBar1.getValue();
if(value5 < 100){
value5++;
value1++;
if(value5 == 1){
phiE.Eating();
}
progressBar5.setValue(value5);
progressBar1.setValue(value1);
if(value5 == 100){
phiE.Thinking();
progressBar5.setValue(0);
progressBar1.setValue(0);
Mark[9] = 0;//重置标记值
Messagebox messagebox = new Messagebox();
timer5.stop();
}
}
}else{
Messagebox messagebox = new Messagebox();
timer5.stop();
}
}
}
@Override
public void stateChanged(ChangeEvent arg0) {

}
}
结果如下截图显示:

选择哲学家 A 就餐:
选择哲学家 B 就餐:

C、D、E 就餐亦一致。

当组合就餐时:

选定 ABC 就餐:
AC 会先就餐,再到 B 就餐

选定 ABCDE 一起就餐:先进行 AC 就餐、再进行 BD 就餐,最后 E 就餐

You might also like