基于环形队列的生产消费模型
pspace_sem_&&cdata_sem_
生产者关注的是环形队列当中是否有空间,只要有空间生产者就可以进行生产。
消费者关注的是环形队列当中是否有数据,只要有数据消费者就可以进行消费
用信号量来描述环形队列当中的空间资源(pspace_sem_)和数据资源(cdata_sem_),在我们初始信号量时给它们设置的初始值是不同的:
pspace_sem_的初始值设置为环形队列的容量,因为刚开始时环形队列当中全是空间。
cdata_sem_的初始值设置为0,因为刚开始时环形队列当中没有数据
生产者申请资源&&消费者释放资源
生产者每次生产数据前都需要先申请pspace_sem_:
- pspace_sem_的值不为0,则信号量申请成功,此时生产者可以进行生产操作。
- pspace_sem_的值为0,则信号量申请失败,此时生产者需要在pspace_sem_的等待队列下进行阻塞等待,直到环形队列当中有新的空间后再被唤醒
当生产者生产完数据后,应该释放cdata_sem_:
- 生产者生产完数据,应该对cdata_sem_进行V操作
- 生产者在生产数据前申请到的是pspace_sem_位置,当生产者生产完数据后,该位置当中存储的是生产者生产的数据,在该数据被消费者消费之前,该位置不再是空间位置,而应该是数据位置
- 当生产者生产完数据后,意味着环形队列当中多了一个数据位置,因此我们应该对cdata_sem_进行V操作。
消费者每次消费数据前都需要先申请cdata_sem_:
- cdata_sem_的值不为0,则信号量申请成功,此时消费者可以进行消费操作。
- cdata_sem_的值为0,则信号量申请失败,此时消费者需要在cdata_sem_的等待队列下进行阻塞等待,直到环形队列当中有新的数据后再被唤醒
当消费者消费完数据后,应该释放pspace_sem_:
- 消费者在进行消费前是对cdata_sem_进行的P操作,但是当消费者消费完数据,应该对pspace_sem_进行V操作
- 消费者在消费数据前申请到的是数据位置,当消费者消费完数据后,该位置当中的数据已经被消费过了,再次被消费就没有意义了,为了让生产者后续可以在该位置生产新的数据,将该位置算作空间位置
- 当消费者消费完数据后,意味着环形队列当中多了一个空间位置,因此我们应该对pspace_sem_进行V操作
在基于环形队列的生产者和消费者模型当中,生产者和消费者必须遵守以下几点
生产者和消费者在访问环形队列时
1、在环形队列为数据为空,或者数据满了 ,生产者和消费者会指向同一位置,如果在环形队列为数据为空,只能由生产者访问,如果在环形队列为数据数据满了,只能由消费者访问
2、环形队列中的数据不空和不满的时候,生产者和消费者一定指向不同的位置,生产者和消费者可以同时访问
3、生产者从消费者的位置开始一直按顺时针方向进行生产,如果生产者生产的速度比消费者消费的速度快,那么当生产者绕着消费者生产了一圈数据后再次遇到消费者,此时生产者就不应该再继续生产了,因为再生产就会覆盖还未被消费者消费的数据
4、消费者从生产者的位置开始一直按顺时针方向进行消费,如果消费者消费的速度比生产者生产的速度快,那么当消费者绕着生产者消费了一圈数据后再次遇到生产者,此时消费者就不应该再继续消费了,因为再消费就会消费到缓冲区中保存的废弃数据
POSIX信号量
信号量的本质描述临界资源中资源数目的计数器
信号量的PV操作:
P操作:我们将申请信号量称为P操作,申请信号量的本质就是申请获得临界资源中某块资源的使用权限,当申请成功时临界资源中资源的数目应该减一,因此P操作的本质就是让计数器减一。
V操作:我们将释放信号量称为V操作,释放信号量的本质就是归还临界资源中某块资源的使用权限,当释放成功时临界资源中资源的数目就应该加一,因此V操作的本质就是让计数器加一
信号量函数
sem_init,初始化信号量
int sem_init(sem_t *sem, int pshared, unsigned int value);
- sem:需要初始化的信号量。
- pshared:传入0值表示线程间共享,传入非零值表示进程间共享。
- value:信号量的初始值(计数器的初始值)
return val :
初始化信号量成功返回0,失败返回-1
POSIX信号量和System V信号量作用相同,都是用于同步操作,达到无冲突的访问共享资源目的,但POSIX信号量可以用于线程间同步。
sem_destroy,销毁信号量
int sem_destroy(sem_t *sem);
- sem:需要销毁的信号量。
return val :
销毁信号量成功返回0,失败返回-1
sem_wait,等待信号量
int sem_wait(sem_t *sem);
- sem:需要等待的信号量
return val :
等待信号量成功返回0,信号量的值减一。
等待信号量失败返回-1,信号量的值保持不变
sem_post,发布信号量
int sem_post(sem_t *sem);
- sem:需要发布的信号量
return val :
发布信号量成功返回0,信号量的值加一。
发布信号量失败返回-1,信号量的值保持不变