linux c 信号量,linux c 生产者与消费者问题 信号量(sem_t)

信号量:

信号量提供两种特殊得操作P(s)与V(s)。

P(s):如果s为非零,P将s减一,然后立即返回。如果s为零,那么就挂起线程,直到s变为非零,而V操作会重启这条线程。在重启之后,P操作将s减1,并将控制权返回给调用者。

V(s):V操作将s加1。如果有任何线程P等待s变为非零的话,那么V就会重启其中一条线程,然后将程序的s减一,完成它的P操作。

在 Linux semaphore.h

中的P和V操作,

P(s)=sem_wait(sem_t*),V(s)=sem_post(sem_t*),下面我们用到的。

生产者与消费者问题:

1。什么是生产者与消费者问题?就是生产者和消费者共用一个缓冲区,生产者生产项目放进缓冲区,而消费者则从缓冲区中消费项目。当缓冲区满了的时候,生产者不能对其生产;而当缓冲区为空的时候,消费者不能作消费。

2。这个问题在现实系统中也运用得非常广泛。例如,在一个多媒体系统中,生产者编码视频帧,而消费者解码并在屏幕上呈现出来。缓冲区得目的是为了减少视频流的抖动,而这种抖动是由各个帧的编码和解码时与数据相关的差异引起得。缓冲区为生产者提供了一个槽位置,而为消费者提供了一个以编码的帧池。

实战代码:

缓冲区结构:

typedefstruct__Buf {

int*buf;// 缓冲区

intn;// 最大缓冲区

inthead;// 缓冲区头

inttail;// 缓冲区尾

sem_t items; // 锁定对不存在项目的缓冲区进行操作的消费者

sem_t slots; // 锁定对已满缓冲区进行操作的生产者

sem_t mutex; // 确保同时只能有一个消费者或生产者对缓存区进行操作

} Buf;

生产与消费:

// 生产者插入项目

voidinsert(Buf *b,intitem) {

sem_wait(&b->slots);

sem_wait(&b->mutex);

// 插入数据

b->buf[(++b->tail)%b->n] = item;

sem_post(&b->mutex);

// post等价於把信号量加一,令消费者能对缓冲区操作(说明缓冲区状态为非空)

sem_post(&b->items);

}

// 消费者获取项目

intget(Buf *b) {

intitem;

sem_wait(&b->items);

sem_wait(&b->mutex);

// 获取数据(意义上是删除了缓冲区中一个项目)

item = b->buf[(++b->head)%b->n];

sem_post(&b->mutex);

// post等价于把信号量加一,令生产者能对缓冲区操作(说明缓冲区状态为未满)

sem_post(&b->slots);

returnitem;

}

完整代码:

#include

#include

#include

#include

#include

typedefstruct__Buf {

int*buf;// 缓冲区

intn;// 最大缓冲区

inthead;// 缓冲区头

inttail;// 缓冲区尾

sem_t items; // 锁定对不存在项目的缓冲区进行操作的消费者

sem_t slots; // 锁定对已满缓冲区进行操作的生产者

sem_t mutex; // 确保同时只能有一个消费者或生产者对缓存区进行操作

} Buf;

// 声明缓冲区

Buf g_buf;

// 生产者插入项目

voidinsert(Buf *b,intitem) {

sem_wait(&b->slots);

sem_wait(&b->mutex);

// 插入数据

b->buf[(++b->tail)%b->n] = item;

sem_post(&b->mutex);

// post等价於把信号量加一,令消费者能对缓冲区操作(说明缓冲区状态为非空)

sem_post(&b->items);

}

// 生产者线程

void*manufacturer(void*) {

inti=0;

for(i=0; i<100; ++i) {

insert(&g_buf, i);

}

return0;

}

// 消费者获取项目

intget(Buf *b) {

intitem;

sem_wait(&b->items);

sem_wait(&b->mutex);

// 获取数据(意义上是删除了缓冲区中一个项目)

item = b->buf[(++b->head)%b->n];

sem_post(&b->mutex);

// post等价于把信号量加一,令生产者能对缓冲区操作(说明缓冲区状态为未满)

sem_post(&b->slots);

returnitem;

}

// 消费者线程

void*consumer(void*) {

inti=0, data;

for(i=0; i<100; ++i) {

data = get(&g_buf);

printf("consumer: %d\n", data);

// 消费者睡300ms, 测试一下看看生产者会不会把缓冲区溢出

usleep(1000*300);

}

return0;

}

intmain() {

pthread_t tid_man, tid_con;

// 设置缓冲区

g_buf.n = 5;

g_buf.buf = (int*)malloc(g_buf.n*sizeof(int));

sem_init(&g_buf.mutex, 0, 1);

sem_init(&g_buf.slots, 0, g_buf.n); // g_buf.n也就是允许插入的数量

sem_init(&g_buf.items, 0, 0);

g_buf.head = -1;

g_buf.tail = -1;

// 创建生产者与消费者线程

pthread_create(&tid_man, 0, manufacturer, 0);

pthread_create(&tid_con, 0, consumer, 0);

// 释放已申请的资源

pthread_join(tid_man, 0);

pthread_join(tid_con, 0);

sem_destroy(&g_buf.items);

sem_destroy(&g_buf.slots);

sem_destroy(&g_buf.mutex);

return0;

}

备注:本人编程新手,如有出错请多多指点,谢谢。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值