最近,有一课下作业要求我们使用互斥量或者信号量来解决线程的同步问题(男女浴室问题),没办法,学渣嘛,自己就上网找答案咯,可是搜了N多发现,他们写的基本都是错的(要么线程没控制好,要么产生死锁)。无奈.png,只能自己写写咯。话不多少先把任务贴上去。
任务要求:
男女共浴(或过桥问题)(引自 AST《现代操作系统》 3th, P98)。
1. 假设一个大学为了卖弄其政治上的正确性,准备把美国最高法院的信条“平等但隔
离其本身就是不平等”既运用在种族上也运用在性别上,从而结束校园内长期使用
的浴室按性别隔离的做法。但是,为了迁就传统习惯,学校颁布法令:当有一个女
生在浴室里,那么其他女生可以进入,但是男生不行,反之亦然。在每个浴室的门
上有一个滑动指示符号,表示当前处于以下三种可能状态之一:
空
有女生
有男生
用你偏好的程序设计语言编写下面过程(可以随意采用所希望的计数器和同步技
术):
woman_wants_to_enter
man_wants_to_enter
woman_leaves
man_leaves
思路:
首先,我们先读懂题意,例如,当浴室开始营业时,第一个到达的是女生,那么女生这个性别就获得了该浴室的所有权,那么对于线程来说,那么这个女生线程就获得了锁,那么其他女生到达浴室门口时亦可以进去。男生到达浴室门口时,必须阻塞。等到最后一个女生洗完澡并且出来时,男生才可以进去。接触过读者写者、生产者消费者的问题的我们应该可以轻松想到,解决这个问题需要两个共享变量来统计男女人数。(没有接触过以上的问题,这个设计难以下手)。我们把这两个共享变量命名为ManNum,WomanNum。然后我们就需要利用这个两个共享变量来进行同步操作了,问题是对共享变量的操作,我们要使用什么?答案是,我们得用互斥量或者信号量。但我本人更喜欢利用信号量来解决互斥问题。除此之外,我们不应该忽略一个的就是性别锁,它能控制浴室同时只能被一种性别访问。因此,解决这个问题,首先我得使用三个信号量(当然,互斥量也可以)。
设置好三个信号量,这三个信号量分别为mutex(性别互斥锁),mutex_man(对ManNum的操作互斥锁),mutex_woman(对WomanNum的操作互斥锁)。
下面我们就应该对这些信号量进行pv操作了。整个设计关键操作如下(以男生线程为例):
P(mutex_man) //对共享变量的互斥操作,只能允许一个男生线程对其进行操作。
ManNum++
if(ManNum==1){ //第一个男生到达,那么他就要担负起抢占性别锁的任务
P(mutex) //对性别锁进行P操作,抢占性别锁,如果抢占失败则被阻塞,等待女生线程的唤醒。
}
V(mutex_man)//如果抢到了锁,就允许其他男生进入
洗澡...
P(mutex_man)//对共享变量的互斥操作,只能允许一个男生线程对其进行操作。
ManNum-- //男生洗完澡离开时的操作
if(ManNum==0){//最后一个男生离开时,就要释放性别锁,从而能让女生进入浴室
V(mutex) //释放性别锁
}
V(mutex_man)
源码:
/**************************************************
*功能:在多线程环境下解决线程互斥与同步
*环境:Ubuntu16.04
*
*输入:第一个参数 男生线程数 第二个参数 女生线程数
*输出:男生、女生对浴室(共享资源)的同步与互斥控制。
*制作:Macmanboy
*完成的题目要求:基础部分(已完成)
*测试:程序没有出现死锁与饥饿。
*版本:2017/12/10
*
***************************************************/
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<semaphore.h>
#include<pthread.h>
#include<time.h>
sem_t mutex;//互斥量,性别互斥锁,男女不能同时待在浴室
sem_t mutex_man;//互斥量,不得两个男生同时进入、离开浴室
sem_t mutex_woman;//互斥量,不得两个女生同时进入、离开浴室
sem_t empty;//浴室容量
int ManNum=0;//男生人数
int WomanNum=0;//女生人数
void Shower()//洗澡操作,包括所用时间
{
int ShowerTime=rand()%3+1;
sleep(ShowerTime);
}
void *ManComeIn(void *rank)
{
//模拟男生陆陆续续到来,到来的时间随机
int my_rank=(int)rank;
int ComeInTime=rand()%5+1;
printf("\033[1;37m");//打印白色
printf("男生%d:在%d秒后即将到达浴室!\n",my_rank,ComeInTime);
sleep(ComeInTime);//男生线程睡眠,模拟到达浴室门口的时间是随机的
printf("\033[1;37m");//打印白色
printf("男生%d:到达浴室!\n",my_rank);
sem_wait(&mutex_man);//不能两个男生同时进来
ManNum++; //男生进入人数
if(ManNum==1){
sem_wait(&mutex);//禁止女生进来
}
sem_post(&mutex_man);//其他男生可以进来
sem_wait(&empty);//浴室容量减1操作
printf("\033[1;37m");//打印白色
printf("男生%d:进入浴室洗澡!\n",my_rank);
Shower();//模拟洗澡,洗澡时间长度随机
sem_wait(&mutex_man);//不能两个男生同时离开
ManNum--;
if(ManNum==0){//最后一个男生离开
sem_post(&mutex); //释放浴室性别使用锁
}
sem_post(&mutex_man);//其他男生可以离开
sem_post(&empty);//浴室容量加1
printf("\033[1;37m");
printf("男生%d:离开浴室!\n",my_rank);
}
void *WomanComeIn(void *rank)
{
//模拟女生陆陆续续到来,到来的时间随机
int my_rank=(int)rank;
int ComeInTime=rand()%5+1;
printf(" \033[1;31m");
printf("女生%d:在%d秒后即将到达浴室!\n",my_rank,ComeInTime);
sleep(ComeInTime);//女生线程睡眠,模拟到达浴室门口的时间是随机的
printf(" \033[1;31m");
printf("女生%d:到达浴室!\n",my_rank);
sem_wait(&mutex_woman);//不能两个女生同时进来
WomanNum++;//女生浴室人数
if(WomanNum==1){
sem_wait(&mutex);//禁止男生进来
}
sem_post(&mutex_woman);//其他女生可以进来
sem_wait(&empty);//
printf(" \033[1;31m");
printf("女生%d:进入浴室洗澡!\n",my_rank);
Shower();
sem_wait(&mutex_woman);
WomanNum--;//女生浴室人数
if(WomanNum==0){
sem_post(&mutex); //
}
sem_post(&mutex_woman);//其他女生可以离开
sem_post(&empty);//浴室容量加1
printf(" \033[1;31m");
printf("女生%d:离开浴室!\n",my_rank);
}
int main(int argc,char *argv[]){
srand(time(NULL));//设置时间种子
sem_init(&mutex,1,1);
sem_init(&mutex_man,0,1);
sem_init(&mutex_woman,0,1);
sem_init(&empty,0,5);
int num_man=strtol(argv[1],NULL,10);
int num_woman=strtol(argv[2],NULL,10);
pthread_t *man_handles;
pthread_t *woman_handles;
man_handles=malloc(num_man*sizeof(pthread_t));
woman_handles=malloc(num_woman*sizeof(pthread_t));
for(int i=0;i<num_man;i++)//创建男生线程
pthread_create(&man_handles[i],NULL,ManComeIn,(void*)i);
for(int i=0;i<num_woman;i++)//创建女生线程
pthread_create(&woman_handles[i],NULL,WomanComeIn,(void*)i);
for(int i=0;i<num_man;i++)//
pthread_join(man_handles[i],NULL);
for(int i=0;i<num_woman;i++)//
pthread_join(woman_handles[i],NULL);
sem_destroy(&mutex);
sem_destroy(&mutex_man);
sem_destroy(&mutex_woman);
sem_destroy(&empty);
free(man_handles);
free(woman_handles);
return 0;
}
测试结果:
当然,我们也可以做下面的扩展:
2. 可做下列功能的扩展:
1) 设置一个同性别学生洗澡的时间段,当过此时间段后,想进去浴室的同性别的
学生不允许进入。等全部出浴室后,优先让另一性别的学生进浴室洗澡。
2) 设置浴室的最多容纳人数
扩展部分的代码,作者整理完后就贴上。