操作系统-实验2-PV信号量实践

目录

第1关:生产者消费者问题实践

第2关:进程互斥和同步


第1关:生产者消费者问题实践

任务描述
生产者—消费者之间设置一个具有n个缓存区的缓冲池,生产者进程将他所生产的产品放入一个缓冲区;消费者进程可以从一个缓冲区中取走产品去消费。不允许消费者进程到一个空缓冲去取产品。不允许生产者进程向一个已装满产品且尚未取走的缓冲区投放产品。

使用多线程实现生产者和消费者问题模型,使用锁和信号量控制线程之间的同步。

相关知识
为了完成本关任务,你需要掌握:1.多线程相关的系统调用,2.使用锁控制进程互斥,3.使用信号量控制进程同步

多线程相关的系统调用
include <pthread.h>
创建线程 pthread_create
pthread_create(&thrd1, NULL, (void *)&thread_function, (void *) &some_argument);
线程创建函数包含四个变量,分别为:
1.一个线程变量名,被创建线程的标识 
2. 线程的属性指针,缺省为NULL即可
3. 被创建线程的程序代码 
4. 程序代码的参数 

线程等待 pthread_join
pthread_create调用成功以后,新线程和老线程谁先执行,谁后执行用户是不知道的,这一块取决与操作系统对线程的调度,如果我们需要等待指定线程结束,需要使用pthread_join函数,这个函数实际上类似与多进程编程中的waitpid。 举个例子,以下假设 A 线程调用 pthread_join 试图去操作B线程,该函数将A线程阻塞,直到B线程退出,当B线程退出以后,A线程会收集B线程的返回码。 该函数包含两个参数:

pthread_t th //th是要等待结束的线程的标识
void **thread_return //指针thread_return指向的位置存放的是终止线程的返回状态。
调用实例:pthread_join(thrd1, NULL);
使用锁控制进程互斥
在主线程中初始化锁为解锁状态 
pthread_mutex_t mutex;
pthread_mutex_init(&mutex, NULL);
访问对象时的加锁操作与解锁操作 
加锁 pthread_mutex_lock(&mutex)
释放锁 pthread_mutex_unlock(&mutex)

利用信号量实现进程同步
先引入头文件 #include <semaphore.h>
初始化信号量: int sem_init(sem_t \*sem, int pshared, unsigned int value); 
成功返回0,失败返回-1
参数
sem:指向信号量结构的一个指针
pshared: 不是0的时候,该信号量在进程间共享,否则只能为当前进程的所有线程们共享
value:信号量的初始值
信号量减1操作,当sem=0的时候该函数会堵塞 int sem_wait(sem_t *sem); 
成功返回0,失败返回-1
参数
sem:指向信号量的一个指针
信号量加1操作 int sem_post(sem_t *sem); 
参数与返回同上
销毁信号量 int sem_destroy(sem_t *sem); 
参数与返回同上

编程要求
请参考生产者线程的函数代码实现消费者线程的函数代码,将Consumer()函数补充完整。

测试说明
需要打印出生产者和消费者线程并发执行的情况,并满足题目所示的限制条件
预期输出结果类似下面这样。因为调度次序随机,执行结果可能和这个不同,但需要满足题目限制要求。
Produce one message:1
Consume one message:1
Produce one message:2
Consume one message:2
Produce one message:3
Consume one message:3
Produce one message:4
Consume one message:4
Produce one message:5
Consume one message:5
Produce one message:6
Produce one message:7
Consume one message:6
Consume one message:7
Produce one message:8
Produce one message:9
Consume one message:8
Produce one message:10
Consume one message:9
Consume one message:10

 

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>

#define SIZE 10

int in = 0;
int out = 0;
int buffer[SIZE];
sem_t empty;
sem_t full;
pthread_mutex_t mutex;

void *Producer()
{
    int nextp = 0;
    int i = 0;
	for(; i < 10; ++i)
	{  
		int time = rand() % 10 + 1;
                                usleep(time*100000); 
                                sem_wait(&empty); 
		pthread_mutex_lock(&mutex);
		nextp = nextp + 1;
		buffer[in] = nextp;
		printf("Produce one message:%d\n", nextp);
		fflush(stdout);//printf后请一定调用这句刷新输出缓存
		in = (in + 1) % SIZE;
		pthread_mutex_unlock(&mutex);         //互斥锁解锁
		sem_post(&full);
	}
}

void *Consumer()
{
	 int i = 0;
    for(; i < 10; i++) {
        sem_wait(&full);
        pthread_mutex_lock(&mutex);
        printf("Consume one message:%d\n", buffer[out++]);
        pthread_mutex_unlock(&mutex);
    }
    //请补充消费者线程函数代码
}


int main()
{	
    sem_init(&empty, 0, 10);    //信号量初始化(最多容纳10条消息,容纳了10条生产者将不会生产消息)
	sem_init(&full, 0, 0);		
	pthread_mutex_init(&mutex, NULL);  //互斥锁初始化		
	pthread_t producid;	
	pthread_t consumid;		
	pthread_create(&producid, NULL, Producer, NULL);   //创建生产者线程	
	pthread_create(&consumid, NULL, Consumer, NULL);   //创建消费者线程	
	pthread_join(producid, NULL); 	
	pthread_join(consumid, NULL);   
	sem_destroy(&empty);         //信号量的销毁
	sem_destroy(&full);    
	pthread_mutex_destroy(&mutex);   //互斥锁的销毁
	return 0;
}

第2关:进程互斥和同步

任务描述
桌上有个能盛的下五个水果的空盘子。爸爸不停的向盘中放苹果或桔子,儿子不停的从盘中取出桔子享用,女儿不停的从盘中取出苹果享用。规定三人不能同时从盘中取放水果。试用信号量实现爸爸、儿子和女儿这三个进程之间的同步

相关知识
为了完成本关任务,你需要掌握:1.多线程相关的系统调用,2.使用锁控制进程互斥,3.使用信号量控制进程同步

多线程相关的系统调用
include <pthread.h>
创建线程 pthread_create
pthread_create(&thrd1, NULL, (void *)&thread_function, (void *) &some_argument);
线程创建函数包含四个变量,分别为:
1.一个线程变量名,被创建线程的标识 
2. 线程的属性指针,缺省为NULL即可
3. 被创建线程的程序代码 
4. 程序代码的参数 

线程等待 pthread_join
pthread_create调用成功以后,新线程和老线程谁先执行,谁后执行用户是不知道的,这一块取决与操作系统对线程的调度,如果我们需要等待指定线程结束,需要使用pthread_join函数,这个函数实际上类似与多进程编程中的waitpid。 举个例子,以下假设 A 线程调用 pthread_join 试图去操作B线程,该函数将A线程阻塞,直到B线程退出,当B线程退出以后,A线程会收集B线程的返回码。 该函数包含两个参数:
pthread_t th //th是要等待结束的线程的标识
void **thread_return //指针thread_return指向的位置存放的是终止线程的返回状态。
调用实例:pthread_join(thrd1, NULL);

#### 使用锁控制进程互斥
在主线程中初始化锁为解锁状态 
pthread_mutex_t mutex;
pthread_mutex_init(&mutex, NULL);
访问对象时的加锁操作与解锁操作 
加锁 pthread_mutex_lock(&mutex)
释放锁 pthread_mutex_unlock(&mutex)
#### 利用信号量实现进程同步
先引入头文件#include <semaphore.h>
初始化信号量: int sem_init(sem_t *sem, int pshared, unsigned int value); 
成功返回0,失败返回-1
参数
sem:指向信号量结构的一个指针
pshared: 不是0的时候,该信号量在进程间共享,否则只能为当前进程的所有线程们共享
value:信号量的初始值
信号量减1操作,当sem=0的时候该函数会堵塞 int sem_wait(sem_t *sem); 
成功返回0,失败返回-1
参数
sem:指向信号量的一个指针
信号量加1操作 int sem_post(sem_t *sem); 
参数与返回同上
销毁信号量 int sem_destroy(sem_t *sem); 
参数与返回同上
### 编程要求
请参考爸爸线程的函数代码实现儿子和女儿线程的函数代码,将Son()函数和Daughter()函数补充完整。
### 测试说明
需要打印出爸爸、儿子和女儿线程并发执行的情况,并满足题目所示的限制条件。
爸爸、儿子和女儿的程序流程如下:
semaphore empty = 5,orange = 0,apple = 0, mutex = 1;
Dad() {
  while(1) {
    wait(empty);
    wait(mutex);
    将水果放入盘中;
    signal(mutex);
    if(放入的是桔子) signal(orange);
    else signal(apple);
  }
}
Son() {
  while(1) {
    wait(orange);
    wait(mutex);
    从盘中取出一个桔子;
    signal(mutex);
    signal(empty);
    享用桔子;
  }
}
Daughter() {
  while(1) {
    wait(apple);
    wait(mutex);
    从盘中取出一个苹果;
    signal(mutex);
    signal(empty);
    享用苹果;
  }
}
输出结果参考如下:
爸爸放入了一个苹果
女儿取了一个苹果
爸爸放入了一个桔子
儿子取了一个桔子
爸爸放入了一个苹果
女儿取了一个苹果
爸爸放入了一个桔子
儿子取了一个桔子
爸爸放入了一个苹果
女儿取了一个苹果
爸爸放入了一个桔子
儿子取了一个桔子
爸爸放入了一个苹果
女儿取了一个苹果
爸爸放入了一个桔子
儿子取了一个桔子
爸爸放入了一个苹果
女儿取了一个苹果
爸爸放入了一个桔子
儿子取了一个桔子
---
开始你的任务吧,祝你成功!
 

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <semaphore.h>
#include <pthread.h>


sem_t apple;
sem_t orange;
sem_t empty;
pthread_mutex_t mutex;

void *Dad()
{
	int nextp = 0;
	int i = 0;
    for(i = 0; i < 10; ++i)
	{
		int time = rand() % 10 + 1;          //随机使程序睡眠0点几秒
		usleep(time*100000);        
		sem_wait(&empty); 
		pthread_mutex_lock(&mutex);
		if(nextp == 0)
		{
			printf("爸爸放入了一个苹果\n");
		}
		else
		{
			printf("爸爸放入了一个桔子\n");
		}
        fflush(stdout);
		
		pthread_mutex_unlock(&mutex);         //互斥锁解锁
		
		if(nextp == 0)
		{
			sem_post(&apple);
		}
		else
		{
			sem_post(&orange);
		} 
		nextp = 1 - nextp; 
	}
}

void *Daughter()
{
	while(1)
	{
		int time = rand() % 10 + 1;          //随机使程序睡眠0点几秒
		usleep(time * 100000);        
		sem_wait(&apple); 
		pthread_mutex_lock(&mutex);
		printf("女儿取了一个苹果\n") ;
        fflush(stdout);
		pthread_mutex_unlock(&mutex);         //互斥锁解锁
		sem_post(&empty);
	}
}

void *Son()
{
		int time = rand() % 10 + 1;  
		usleep(time * 100000);        
		sem_wait(&orange); 
		pthread_mutex_lock(&mutex);
		printf("儿子取了一个桔子\n") ;
        fflush(stdout);
		pthread_mutex_unlock(&mutex);       
		sem_post(&empty); 
    //请添加儿子线程的函数代码
}


int main()
{			
    sem_init(&empty, 0, 5);    //信号量初始化
	sem_init(&orange, 0, 0);
	sem_init(&apple, 0, 0);		
	pthread_mutex_init(&mutex, NULL);  //互斥锁初始化		
	pthread_t dadid;	
	pthread_t daughterid;
	pthread_t sonid;		
	pthread_create(&dadid, NULL, Dad, NULL);   //创建爸爸线程	
	pthread_create(&daughterid, NULL, Daughter, NULL);   //创建女儿线程
	pthread_create(&sonid, NULL, Son, NULL);   //创建儿子线程		
	pthread_join(daughterid, NULL);
	pthread_join(sonid, NULL);   
	
	sem_destroy(&empty);         //信号量的销毁
	sem_destroy(&apple);
	sem_destroy(&orange);    

	

	pthread_mutex_destroy(&mutex);   //互斥锁的销毁

	

	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值