您的位置:首页 > 其它

生产者-消费者模型

2017-04-07 17:47 183 查看
在写生产者—消费者模型时,先谈及一个概念——信号量。

sem函数:

(1)sem_init函数是Posix信号量操作中的函数。

sem_init() 初始化一个定位在 sem 的匿名信号量。

value 参数指定信号量的初始值。 pshared 参数指明信号量是由进程内线程共享,还是由进程之间共享。如果 pshared 的值为 0,那么信号量将被进程内的线程共享,并且应该放置在这个进程的所有线程都可见的地址上(如全局变量,或者堆上动态分配的变量)。

函数原型:int sem_init(sem_t *sem, int pshared, unsigned int value);

如果 pshared 是非零值,那么信号量将在进程之间共享,并且应该定位共享内存区域(见 shm_open(3)、mmap(2) 和 shmget(2))。因为通过 fork(2) 创建的孩子继承其父亲的内存映射,因此它也可以见到这个信号量。所有可以访问共享内存区域的进程都可以用 sem_post(3)、sem_wait(3) 等等操作信号量。初始化一个已经初始的信号量其结果未定义。

(2)sem_wait函数也是一个原子操作,它的作用是从信号量的值减去一个“1”,但它永远会先等待该信号量为一个非零值才开始做减法。//P操作

也就是说,如果你对一个值为2的信号量调用sem_wait(),线程将会继续执行,将信号量的值将减到1。如果对一个值为0的信号量调用sem_wait(),这个函数就会原地等待直到有其它线程增加了这个值使它不再是0为止。如果有两个线程都在sem_wait()中等待同一个信号量变成非零值,那么当它被第三个线程增加 一个“1”时,等待线程中只有一个能够对信号量做减法并继续执行,另一个还将处于等待状态。sem_trywait(sem_t *sem)是函数sem_wait的非阻塞版,它直接将信号量sem减1,同时返回错误代码。

函数原型 :int sem_wait(sem_t * sem);

sem_wait() 减小(锁定)由sem指定的信号量的值.如果信号量的值比0大,那么进行减一的操作,函数立即返回.

  如果信号量当前为0值,那么调用就会一直阻塞直到或者是信号量变得可以进行减一的操作

  (例如,信号量的值比0大),或者是信号处理程序中断调用

sem_trywait() 和 sem_wait()是一样的,除了如果不能够对信号量立即进行减一,

  那么sem_trywait()就会返回一个错误(错误号是AGAIN)而不是锁定. //非阻塞式等待

  sem_timedwait() 和 sem_wait()是一样的,除了如果减一操作不能立即执行的话,

  

(3)sem_destroy() 销毁由sem指向的匿名信号量。

函数原型:int sem_destroy(sem_t *sem);

sem_destroy() 销毁由sem指向的匿名信号量。

只有通过sem_init(3) 初始化的信号量才应该使用sem_destroy() 销毁。

销毁一个有其它线程或进程当前阻塞(在sem_wait(3))的信号量将导致未定义行为。

使用一个已经销毁的信号量将导致未定义结果,除非这个信号量已经使用sem_init(3) 重新初始化了。

返回值:sem_destroy() 成功时返回 0;错误时,返回 -1,并把errno设置为合适的值。

(4)sem_post是给信号量的值加上一个“1”,它是一个“原子操作”---即同时对同一个信号量做加“1”操作的两个线程是不会冲突的;而同 时对同一个文件进行读、加和写操作的两个程序就有可能会引起冲突。//V操作

函数原型:int sem_post(sem_t *sem);

信号量的值永远会正确地加一个“2”--因为有两个线程试图改变它。 当有线程阻塞在这个信号量上时,调用这个函数会使其中一个线程不在阻塞,选择机制是有线程的调度策略决定的。

返回值:sem_post() 成功时返回 0;错误时,信号量的值没有更改,-1 被返回,并设置 errno 来指明错误。

生产者-消费者模型(环形队列实现)

(1)用计数器实现判空,判满

(2)在队列为空时,保证生产者先进行,队列为满时,消费者先进行

代码如下:







源代码如下:

#include<stdio.h>
#include<unistd.h>
#include<pthread.h>
#include<semaphore.h>
#include<stdlib.h>
#define SIZE 64     //环形队列大小64
sem_t blanks;    //格子
sem_t datas;     //数据

int ring[SIZE];

void* producer(void* arg)
{
static int i = 0;
while(1)
{
sem_wait(&blanks);
int num = rand()%1000;
ring[i++] = num;
printf("producer:%d, tid:%lu\n", num, pthread_self());
i %= SIZE;
sem_post(&datas);                                       }
sleep(1);
}

void* consumer(void* arg)
{
static int i=0;
while(1)
{
sem_wait(&datas);
int num = ring[i++];
printf("consumer: %d, tid:%lu\n:", pthread_self());
i %= SIZE;
sem_post(&blanks);
sleep(1);
}
}

int main()
{
pthread_t id1, id2;
sem_init(&blanks, 0, SIZE);
sem_init(&datas, 0, 0);
pthread_create(&id1, NULL, producer, NULL);
pthread_create(&id2, NULL, consumer, NULL);
sem_destroy(&blanks);
sem_destroy(&datas);
pthread_join(id1, NULL);
pthread_join(id2, NULL);
return 0;
}


运行结果如下:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  sem producer consumer