重庆大良网站建设,网站域名推广,wordpress 模板 使用,手机制作app需要什么软件文章目录 信号量原理信号量保证同步和互斥的原理探究信号量相关函数初始化信号量函数等待信号量函数释放信号量函数销毁信号量函数 信号量实现生产者消费者模型 信号量原理
信号量的原理#xff1a;资源计数器 PCB等待队列 函数接口
资源计数器#xff1a;对共享资源的计… 文章目录 信号量原理信号量保证同步和互斥的原理探究信号量相关函数初始化信号量函数等待信号量函数释放信号量函数销毁信号量函数 信号量实现生产者消费者模型 信号量原理
信号量的原理资源计数器 PCB等待队列 函数接口
资源计数器对共享资源的计数 当执行流获取信号量成功后信号量当中的计数器减一如果获取失败该执行流就会被放入PCB等待队列中 当执行流释放信号量成功之后信号量当中的计数器会进行加一操作
PCB等待队列用于存放等待信号量的线程
函数接口用于操作信号量的一组函数
信号量保证同步和互斥的原理探究
信号量不仅仅可以完成线程之间的同步与互斥也可以完成进程之间的同步与互斥 互斥原理 1、初始化信号量后信号量当中的计数器保存的值为1表示只有一个资源可以被使用
2、当执行流A想要访问共享资源时首先获取信号量此时计数器中的值为1表示可以访问执行流获取到信号量后计数器的值从1变成0执行流A此时去访问共享资源
3、此时执行流B希望去访问共享资源首先它要获取信号量但是信号量中的计数器中的值为0表示无法获取该信号量进行无法访问共享资源因为执行流B的PCB被放进了PCB等待队列中等待目标信号量的释放同时信号量当中的计数器的值进行减一操作计数器中的值变成了-1这里的-1表示当前还有1个执行流在等待访问共享资源 同步原理 1、当执行流想要访问共享资源时首先需要获取信号量
2、如果信号量中的计数器的值大于0则表示能够获取信号量进而可以访问共享资源
3、如果信号量中计数器的值小于或等于0则表示不能获取信号量进而无法访问共享资源该执行流被放入PCB等待队列中同时计数器进行减一操作
4、当释放信号量的时候会对信号量中计数器进行加一操作
5、如果信号量中的计数器大于0则唤醒PCB等待队列中的线程
6、如果信号量中的计数器小于或等于0则不唤醒PCB等待队列中的线程
信号量相关函数
POSIX信号量的函数的名字都是以sem_开头常用的POSIX信号量函数有以下这些
#include semaphore.h
int sem_init(sem_t *sem, int pshared, unsigned int value);
int sem_destroy(sem_t *sem);int sem_wait(sem_t *sem);
int sem_trywait(sem_t *sem);
int sem_timedwait(sem_t *sem, struct timespec*abs_timeout);sem_t是信号量的类型sem_t是一个结构体其中有资源计数器和PCB等待队列
sem_t源码:
typedef union
{char __size[__SIZEOF_SEM_T];long int __align;
} sem_t;初始化信号量函数
int sem_init(sem_t *sem, int pshared, unsigned int value);功能初始化一个信号量
参数
sem指向被操作的信号量传入信号量的地址pshared表示该信号量是用于进程间的还是用于线程间的填入以下的值
数值含义0用于线程间全局变量非0用于进程间将信号量所用到的资源在共享内存当中进行开辟
value资源的个数本质上就是计数器的值
等待信号量函数
int sem_wait(sem_t *sem);功能
执行流调用该函数后将会对计数器进行减一操作–p操作P 操作用于获取或锁定信号量信号量的计数器自己保证原子性操作不会因为多线程而导致程序计数器中的结果二义性减一操作一步完成。
如果减一操作后计数器的值大于0表示其他执行流仍然可以访问共享资源
如果减一操作后计数器的值等于0表示该执行流可以访问共享资源其他执行流若想访问需要进入PCB等待队列
如果减一操作后计数器的值小于0表示当前执行流需要进入PCB等待队列其他执行流若想访问也需要进入PCB等待队列
参数sem指向被操作的信号量传入信号量的地址
要注意的是先获取信号量再获取互斥锁先获取信号量再保证互斥就是说接口一定是先对程序计数器进行减一操作再拿到锁假设如果先拿到锁再进行信号量减一那么当拿到锁之后信号量如果从0减为小于0的数字那么执行流就会被放到PCB等待队列中去了这个函数也没有传输互斥锁所以内部不会进行解锁所以这时线程就会带着锁进行等待队列然后无法解锁锁一直被锁着其他临界区也无法访问当前临界区资源
释放信号量函数
int sem_post(sem_t *sem);功能
执行流调用该函数后将会对计数器进行加一操作–v操作V 操作用于释放或解锁信号量 判断资源计数器的值是否小于等于0
之所以还要判断是否等于0是因为假设有一个生产者队列和一个消费者队列当生产者将队列生产满了之后假设此时程序计数器为-1而将程序计数器减为-1的那个线程还在等待队列中此时消费者线程被生产者唤醒消费数据出队它将生产者信号量计数器中加一变成0那么此时也要通知等待队列中的生产者线程出来工作
是通知PCB等待队列
否不用通知PCB等待队列因为没有线程在等待
参数sem指向被操作的信号量传入信号量的地址
销毁信号量函数
int sem_destroy(sem_t *sem);
功能销毁目标信号量
参数sem指向被操作的信号量传入信号量的地址
信号量实现生产者消费者模型
代码如下
#includepthread.h
#includesemaphore.h
#includestdio.h
#includequeue
#includeiostream
#define CAPACITY 4
#define THREAD_COUNT 2
int g_val 0;
using namespace std;
class Safe_Queue{
public:Safe_Queue(){capacity_ CAPACITY;sem_init(lock_, 0, 1);//锁的信号量资源要么为0表示不可用要么为1表示可用sem_init(cons_sem_, 0, 0);//消费者的信号量最开始的时候队列为空所以消费者没有资源可用sem_init(prod_sem_, 0, capacity_);//生产者的信号量最开始的时候队列为空所以生产者可用资源数就是队列大小}~Safe_Queue(){sem_destroy(lock_);sem_destroy(prod_sem_);sem_destroy(cons_sem_);}//插入接口-生产者调用void Push(int data){sem_wait(prod_sem_);//等待信号量执行过后对计数器进行减一操作sem_wait(lock_);//获取访问_que资源_que.push(data);printf(I am product, I product %d\n, data);//sem_post(cons_sem_);//对消费者可用的资源计数加一sem_post(lock_);//释放信号量函数执行过后对计数器进行加一操作sem_post(cons_sem_);//对消费者可用的资源计数加一}//获取元素接口-消费者调用int Pop(){sem_wait(cons_sem_);sem_wait(lock_);int temp _que.front();_que.pop();printf(I am consume, I consume %d\n, temp);//sem_post(prod_sem_);sem_post(lock_);sem_post(prod_sem_);return temp;}
private://STL中的queue是线程不安全的所以需要进行保护queueint _que;sem_t lock_;//用来保证队列资源互斥的信号量sem_t prod_sem_;//生产者的信号量sem_t cons_sem_;//消费者的信号量size_t capacity_;//人为约定队列的大小
};
void* cons_start(void* arg){Safe_Queue *q (Safe_Queue*)arg;while(1){q-Pop();}return NULL;
}
void* prod_start(void* arg){Safe_Queue *q (Safe_Queue*)arg;int data 0;while(1){q-Push(data);data;}return NULL;
}
int main(){Safe_Queue *q new Safe_Queue();if(q NULL) return 0;pthread_t cons[THREAD_COUNT], prod[THREAD_COUNT];for(int i0; iTHREAD_COUNT; i){int ret pthread_create(prod[i], NULL, prod_start, (void*)q);if(ret 0){perror(pthread_create);return 0;}ret pthread_create(cons[i], NULL, cons_start, (void*)q);if(ret 0){perror(pthread_create);return 0;}}for(int i0; iTHREAD_COUNT; i){pthread_join(cons[i], NULL);pthread_join(prod[i], NULL);}return 0;
}执行结果