首页 > 程序开发 > 软件开发 > 其他 >

生产者与消费者模型(二)

2017-07-04

生产者与消费者模型(二),也掌握了生产者与消费者模型的规则,并且实现了基于单链表的生产者与消费者模型,但是我们实现的基于单链表的生产者与消费者模型还是存在问题,存在死锁的问题,如果想深入理解死锁问题的,可以去看下我总结的死锁。

生产者与消费者模型(二),也掌握了生产者与消费者模型的规则,并且实现了基于单链表的生产者与消费者模型,但是我们实现的基于单链表的生产者与消费者模型还是存在问题,存在死锁的问题,如果想深入理解死锁问题的,可以去看下我总结的死锁。

这篇博客我们主要来实现基于环形队列的生产者与消费者模型。
由于上一篇博客已经讲清楚了关于生产者与消费者的各种问题,所以这篇博客我们就直接来实现。

使用环形队列模拟实现不带锁的单生产者与单消费者模型的思路:

这里写图片描述

生产者与消费者遵循两个规则:

1.消费者永远都在生产者的后面。

(如果消费者可以超过生产者的话,那么消费者可能会读取到垃圾数据)。

2.生产者永远不能将消费者包围一圈

(如果生产者的优先级很高,消费者的优先级很低,如果生产者可以将消费者包围一圈,那么生产者可能就会覆盖掉原来的旧数据(消费者还没来得及消费的数据))。

由上面的两条规则可知:

1.当生产者将环形队列写满时,这时生产者会被挂起等待。(等待数据被消费者读取走)。

2.当消费者将环形队列中的数据读取完时,这时消费者就会被挂起等待。(等待写入生产者写入的新的数据)。

实现基于环形队列的生产者与消费者模型(不带锁)

#include

#include

#include 

int blank[64];

sem_t semBlank;//空格子的信号量

sem_t semData;//数据的信号量

//消费者读数据

void *consumer(void *arg)

{

//p

int step = 0;//每次读取数据的下标

while(1)

{

sem_wait(&semData);//等待数据信号量(p操作)

//下面两行是临界区

int data = blank[step];

printf("consume done... %d\n",data);

step++;

sem_post(&semBlank);//释放格子资源(v操作)

step %= 64;//保证下标不越界

// sleep(1);

}

}

void *producter(void *arg)

{

int step = 0;

while(1)

{

sem_wait(&semBlank);//等待格子资源(p操作--)

int data = rand()%1234;

blank[step] = data;

printf("product done... %d\n",data);

step++;

sem_post(&semData);//释放数据资源(v操作++)

step %= 64;

sleep(2);

}

}

int main()

{

sem_init(&semBlank,0,64);

sem_init(&semData,0,0);

pthread_t c,p;

pthread_create(&c,NULL,consumer,NULL);

pthread_create(&p,NULL,producter,NULL);

pthread_join(c,NULL);

pthread_join(p,NULL);

sem_destroy(&semBlank);

sem_destroy(&semData);

return 0;

}

结果如下:

这里写图片描述

信号量有关操作函数:

1.用sem_init来初始化一个信号量变量:

这里写图片描述

返回值:
成功返回0,错误返回-1.

参数:

sem:定义的信号量变量的地址;
pshared:如果设置为0,说明这个信号量用于同一个进程的多个线程之间同步的。
如果不为0,则说明这个信号量是在多个进程间共享的。一般应该将其存放在共享内存区。
value:信号量要初始的值(意思也是可用资源的数量)。

2、在使用完信号量之后应该释放与信号量相关的资源。

这里写图片描述

3.获得资源(P操作)

这里写图片描述

上面三种情况:
第一种sem_wait通俗点理解,使得信号量的值减一,如果这时的信号变量是0,那么就将该线程/进程挂起等待,也就是阻塞式等待。
第二种sem-trywait是非阻塞等待,如果资源不就绪,那么就返回错误码。

4.释放资源(v操作)
使得信号量的值加1,同时唤醒挂起等待的线程或进程。

这里写图片描述

返回值:成功返回0,失败返回-1并设置错误码。
描述:
调用该函数可以释放资源(v操作),使得信号量的值加1,同时唤醒挂起等待的线程。

相关文章
最新文章
热点推荐