Linux之posix信号量

    xiaoxiao2022-07-04  288

    今天来讲下POSIX信号量,用于同步操作,达到无冲突的访问共享资源的目的,可以用于线程间同步。

    信号量就是一个计数器+等待队列+等待+唤醒

    1.信号量的基本接口

    1)初始化信号量 int sem_init(sem_t *sem, int pshared, unsigned int value); sem:信号量变量 pshared:0表示线程间共享,非0表示进程间共享(决定用于线程间还是进程间) value:信号量初始值

    2)销毁信号量 int sem_destroy(sem_t *sem);

    3)等待信号量 功能:等待信号量,会将信号量的值减1 int sem_wait(sem_t *sem);

    4)发布信号量 功能:发布信号量,表示资源使用完毕,可以归还资源了。将信号量值加1。 int sem_post(sem_t *sem);

    信号量和条件变量的区别: 信号量与条件变量的区别:信号量拥有资源计数的功能,临界资源是否能够操作通过自身技术判断,条件变量是搭配互斥锁一起使用的,信号量还可以实现互斥,计数仅为0/1< font>

    2.信号量实现生产者与消费者模型

    上一节我用基本队列实现了一个生产者与消费者模型,这节我将用信号量和大小固定的环形 队列再次实现生产者与消费者模型:

    实现代码

    1 #include<iostream> 2 #include<pthread.h> 3 #include<vector> 4 #include<semaphore.h> 5 6 //实现线程安全的环形队列,用信号量和线性表实现 7 //信号量就是一个计数器,具有等待队列+等待+唤醒功能 8 9 class RingQueue 10 { 11 public: 12 RingQueue(int cap = 10):queue(10),capacity(cap) //构造函数,采用了初始化列表的形式,定义环形队列大小capacity为10 13 ,write_step(0),read_step(0){ 14 //int sem_init(sem_t *sem, int pshared, unsigned int value); 15 //sem:信号量变量 16 //pshared:决定信号量用于线程还是进程 17 //0为线程 !0为进程 18 //value:信号量初始计数 19 sem_init(&data,0,0); 20 sem_init(&idle,0,cap); 21 sem_init(&lock,0,1); 22 } 23 ~RingQueue(){ //析构函数 24 sem_destroy(&data); 25 sem_destroy(&idle); 26 sem_destroy(&lock); 27 } 28 bool QueuePush(int data){ 29 ProductorWait(); //因为信号量自带一个计数功能,所以不需要在循环判断,先加一个等待是为了判断是否队列空了,如果先加锁然后却发现满了程序就会卡在productorwait()那里没有解锁。 30 QueueLock(); //访问临界资源加锁 31 queue[write_step] = data; //放数据 32 write_step = ((write_step)+1)%capacity; //写指针要改变 33 QueueUnlock(); //访问完毕后解锁,因为锁只是限制临界资源的访问,不限制其他操作 34 ConsumorWakeUp(); //唤醒消费者 35 return true; 36 } 37 bool QueuePop(int *data){ 38 ConsumorWait(); //同理先加一个等待是为了判断是否有资源可以取,否则先加锁了,结果发现没有临界资源可以访问,则会卡在consumorwait()那里没有解锁。 39 QueueLock(); 40 *data = queue[read_step]; //取数据 41 read_step = ((read_step)+1)%capacity; //渎指针要改变 42 QueueUnlock(); 43 ProductorWakeUp(); 44 return true; 45 } 46 private: 47 void QueueLock(){ 48 sem_wait(&lock); 49 } 50 void QueueUnlock(){ 51 sem_post(&lock); 52 } 53 void ConsumorWait(){ 54 sem_wait(&data); 55 } 56 void ConsumorWakeUp(){ 57 sem_post(&data); 58 } 59 void ProductorWait(){ 60 sem_wait(&idle); 61 } 62 void ProductorWakeUp(){ 63 sem_post(&idle); 64 } 65 private: 66 std::vector<int> queue; 67 int capacity; 68 int write_step; 69 int read_step; 70 sem_t data; //代表消费者信号量 71 sem_t idle; //代表生产者信号量 72 sem_t lock; 73 }; 74 75 void* pth_consumor(void* arg) 76 { 77 RingQueue *q = (RingQueue*) arg; 78 while(1){ 79 int data; 80 q->QueuePop(&data); 81 std::cout<<"consumor get data!"<<std::endl; 82 } 83 return NULL; 84 } 85 86 void* pth_productor(void* arg) 87 { 88 RingQueue* q = (RingQueue*) arg; 89 int i=0; 90 while(1){ 91 q->QueuePush(i); 92 std::cout<<"productor put data!"<<std::endl; 93 i++; 94 } 95 return NULL; 96 } 97 98 int main() 99 { 100 pthread_t ctid[4],ptid[4]; 101 int ret,i; 102 RingQueue q; 103 for(i=0;i<4;i++){ 104 ret = pthread_create(&ctid[i],NULL,pth_consumor,(void*)&q); 105 if(ret!=0){ 106 std::cout<<"consumor not exist!"<<std::endl; 107 return -1; 108 } 109 } 110 for(i=0;i<4;i++){ 111 ret = pthread_create(&ptid[i],NULL,pth_productor,(void*)&q); 112 if(ret!=0){ 113 std::cout<<"productor not exist!"<<std::endl; 114 return -1; 115 } 116 } 117 for(i=0;i<4;i++){ //线程等待 118 pthread_join(ctid[i],NULL); 119 } 120 for(i=0;i<4;i++){ 121 pthread_join(ptid[i],NULL); 122 } 123 return 0; 124 }
    最新回复(0)