Semaphore(信号量)
Mutex变量是非0即1的,可看作一种资源的可用数量,初始化时Mutex是1,表示有一个可用资源,加锁时获得该资源,将Mutex减到0,表示不再有可用资源,解锁时释放该资源,将Mutex重新加到1,表示又有了一个可用资源。
信号量(Semaphore)和Mutex类似,表示可用资源的数量,和Mutex不同的是这个数量可以大于1。如果信号量描述的资源数目是1时,此时的信号量和互斥锁相同!
POSIX semaphore库函数,这种信号量不仅可用于同一进程的线程间同步,也可用于不同进程间的同步。
有关函数:
单生产者但消费者模型:
代码说明:
1.push()和pop()的数据(datatype)本篇用的是基本类型,如果是自定义类型的话,需要实现赋值运算符的重载
2.数组实际上是线性的,内存中并没有环形数组,我们定义了一个固定大小的数组,当数组的最后一个元素也被填上数据时,检查数组的第一个元素(下标为0的元素)是否已经被消费者读过,如果已经读过,那么生产者就可以继续放数据,当数组满时(即数组中的元素一个也没有被消费者读),生产者会等待。
3.sem_init()初始化两个信号量sem_p(控制生产者)和sem_c(控制消费者),pshared为0时,表示信号量用于同一进程的线程间同步
sem_destroy()使两个信号量回到初始化前的状态
sem_wait() 可以获得资源,相当于P操作,把给定信号量减一
sem_post() 可以释放资源,相当于V操作,进行加一操作
当信号量的值为0时,sem_wait()会将进程挂起等待,sem_trywait()不会将进程挂起
代码实现:
ring.cpp
#include <iostream> #include <stdlib.h> #include <semaphore.h> #include <pthread.h> using namespace std; #define SEM_PRO 20 #define SEM_CON 0 #define SIZE SEM_PRO typedef int datatype; datatype ring[SIZE];//数组的定义 datatype pro,con; sem_t sem_p;//product sem_t sem_c;//consumer void init_ring(datatype (*ring)[SIZE]) { pro=0; con=0; } datatype& push(datatype &data,int index) { ring[pro++]=data; datatype tmp=ring[pro-1]; pro%=SIZE; return tmp; } datatype& pop(int index) { con++; datatype tmp=ring[con-1]; con%=SIZE; return tmp; } void* product(void* arg) { while(1){ datatype data=rand()%50; sem_wait(&sem_p); datatype val=push(data,pro); cout<<"product done...,val is:"<<val<<endl; sem_post(&sem_c); sleep(1); } } void* consumer(void* arg) { while(1){ sem_wait(&sem_c); datatype val=pop(con); cout<<"consumer done...,val is:"<<val<<endl; sem_post(&sem_p); sleep(8); } } int main() { init_ring(&ring); sem_init(&sem_p,0,SEM_PRO); sem_init(&sem_c,0,0); pthread_t tid1,tid2; pthread_create(&tid1,NULL,product,NULL); pthread_create(&tid2,NULL,consumer,NULL); sem_destroy(&sem_p); sem_destroy(&sem_c); pthread_join(tid1,NULL); pthread_join(tid2,NULL); return 0; }
Makefile
ring:ring.cpp g++ -o [email protected] $^ -lpthread .PHONY:clean clean: rm -f ring
下面两次运行生产者和消费者的速度有所变化,导致运行结果不同
第一次运行结果:
第二次运行结果:
多生产者多消费者模型:(实际上和单生产者单消费者一样,只多加了6行线程创建和等待的代码)
#include <iostream> #include <stdlib.h> #include <semaphore.h> #include <pthread.h> using namespace std; #define SEM_PRO 20 #define SEM_CON 0 #define SIZE SEM_PRO typedef int datatype; datatype ring[SIZE]; datatype pro,con; sem_t sem_p;//product sem_t sem_c;//consumer void init_ring(datatype (*ring)[SIZE]) { pro=0; con=0; } datatype& push(datatype &data,int index) { ring[pro++]=data; datatype tmp=ring[pro-1]; pro%=SIZE; return tmp; } datatype& pop(int index) { con++; datatype tmp=ring[con-1]; con%=SIZE; return tmp; } void* product(void* arg) { while(1){ datatype data=rand()%50; sem_wait(&sem_p); datatype val=push(data,pro); sem_wait(&sem_p); datatype val=push(data,pro); cout<<"product"<<(int)arg<<" done...,val is:"<<val<<endl; sem_post(&sem_c); sleep(1); } } void* consumer(void* arg) { while(1){ sem_wait(&sem_c); datatype val=pop(con); cout<<"consumer"<<(int)arg<<" done...,val is:"<<val<<endl; sem_post(&sem_p); sleep(3); } } int main() { init_ring(&ring); sem_init(&sem_p,0,SEM_PRO); sem_init(&sem_c,0,0); pthread_t tid1,tid2,tid3; pthread_create(&tid1,NULL,product,(void*)1); pthread_create(&tid2,NULL,product,(void*)2); pthread_create(&tid3,NULL,product,(void*)3); pthread_t tid4,tid5; pthread_create(&tid4,NULL,consumer,(void*)4); pthread_create(&tid5,NULL,consumer,(void*)5); sem_destroy(&sem_p); sem_destroy(&sem_c); pthread_join(tid1,NULL); pthread_join(tid2,NULL); pthread_join(tid3,NULL); pthread_join(tid4,NULL); pthread_join(tid5,NULL); return 0; }
运行结果: