Linux多线程之信号量实现生产者消费者模型

信号量(与信号没有任何关系)

【进化版互斥锁 (1–>N)】
由于互斥锁的粒度比较大,如果我么希望在多个线程间对某一对象的部分数据进行共享,使用互斥锁是没有办法实现的,只能将整个数据对象锁住。这样虽然达到了多线程操作共享数据时保证数据正确性的目的,却无形中导致线程的并发性下降。线程从并行执行变化了串行执行。与直接使用单进程无异。
【信号量:是相对折中的一种处理方式,既能保证同步,数据不混乱,又能提高高线程并发】

主要应用函数

1. sem_init  		初始化信号量
2. sem_destroy		销魂信号量
3. sem_wait			申请信号量
4. sem_trywait
5. sem_timedwait
6. sem_post			释放信号量
【以上6个函数返回值都是:成功:0;失败:-1,同时设置errno。(注意,它们没有pthread前缀,意味着不仅仅能够在线程中使用)

sem_init 函数

【初始化信号量】
	int sem_init(sem_t *sem, int pshared, unsigned int value);

sem_destroy 函数

【销毁信号量】
	int sem_destroy(sem_t *sem);

sem_wait 函数

【申请信号量】
int sem_wait(sem_t *sem);
1. 若信号量大于0,则信号量--
2. 若信号量等于0,则造成线程阻塞

sem_post 函数

【释放信号量】
int sem_post(sem_t *sem);
将信号量++,同时唤醒阻塞在信号量上的线程
【注意点】由于sem_t的实现对用户是隐藏的,所以所谓的++--操作只能通过函数来实现,而不能直接用++--符号
【信号量的初值,决定了占用信号量的线程的个数】
练习
  1. 用环形队列模拟临界区,用信号量实现生产者和消费者模型
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <semaphore.h>
#include <pthread.h>

#define NUM 5
int num[NUM]; //定义一个数组实现环形队列
sem_t blank;	//环形队列中的空格数
sem_t product;	//环形队列中的产品数

void *producer(void *arg)
{
	int i = 0;
	while(1)
	{
		sem_wait(&blank);  //生产者将空格数--,为0时阻塞
		num[i] = rand() % 100 + 1;	//生产一个产品
		printf("Produce --- %d\n", num[i]);
		sem_post(&product);	//将产品数++

		i = (i + 1) % NUM;	//借助下标实现环形
		sleep(rand() % 2);	
	}
}
void *customer(void *arg)
{
	int i = 0;
	while(1)
	{
		sem_wait(&product);	//消费者将产品数--,为0时阻塞
		printf("Costume ------------- %d\n", num[i]);	
		num[i] = 0;	//消费一个产品
		sem_post(&blank);	//将空格数++

		i = (i + 1) % NUM;	//借助下标实现环形
		sleep(rand() % 2);
	}
}
int main()
{
	pthread_t pid, cid;
	srand(time(NULL));
	sem_init(&blank, 0, NUM);
	sem_init(&product, 0, 0);

	pthread_create(&pid, NULL, producer, NULL);
	pthread_create(&cid, NULL, customer, NULL);

	pthread_join(pid, NULL);
	pthread_join(cid, NULL);
	return 0;
}

【运行结果】
在这里插入图片描述
3. 揣摩sem_timedwait函数作用。编程实现,一个线程读用户输入,另一个线程打印"hello world"。如果用户无输入,则每隔5秒向屏幕打印一个"hello world";如果有用户输入,立刻打印“hello world”到屏幕

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

sem_t get;//信号量

void *producer(void*arg){
	int i=0;
	while(1){
		struct timespec ts;
		time_t cur = time(NULL); //获取当前时间
		ts.tv_sec = cur + 5;	//每隔5秒
		int r=sem_timedwait(&get, &ts);
		if(r){
			printf("hello world\n");//超时
		}
		else{
			printf("HELLO WORLD\n"); 
		}
	}
}

void *conusm(void*arg){

	while(1){
		system("stty -echo");  //不回显,不在屏幕上显示输入的字符

		//这句代码的作用是,防止把换行符也当做一个字符,如果不加这句,输入一个字符,会打印两句"HELLO WORLD"
		system("stty -icanon");//设置一次性读完操作,如使用getchar()读操作,不需要按enter
		char ch = getchar();
		sem_post(&get);

	}
}

int main(){
	pthread_t p1,p2;

	sem_init(&get,0,0);

	pthread_create(&p1,NULL,producer,NULL);
	pthread_create(&p2,NULL,conusm,NULL);

	pthread_join(p1,NULL);
	pthread_join(p2,NULL);

	sem_destroy(&get);
	return 0;
}

【运行结果】
在这里插入图片描述

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值