信号量
信号量是一个计数器,可用于实现多线程和多进程之间的临界资源访问安全和合理性,即同步与互斥;
这里我主要实现的是线程间的同步与互斥;
信号量分类
信号量可分为:内核信号量和用户信号量
内核信号量:由内核控制路径使用
用户信号量:用户态进程使用的信号量;分为POSIX信号量和SYSTEM V信号量
POSIX信号量又分为有名信号量和无名信号量;
有名信号量:值保存在文件中,可用于进程和线程的安全访问;
无名信号量:值保存在内存中;这次使用POSIX无名信号量;
同步
多线程对临界资源访问的时序合理性;
条件变量实现同步:等待+唤醒+等待队列 ---- 唤醒条件是需要用户自己进行判断的;且条件变量需要和互斥锁搭配使用。
信号量实现同步:因为信号量是一个计数器,可通过自身资源计数来判断对临界资源的操作的可行性。
- 资源计数>0;表示操作可行,可以对临界资源进行访问;直接返回,且资源计数-1;
- 资源<=0;表示无资源可访问,调用阻塞函数;
- 若其他线程产生了一个资源则资源计数+1;唤醒等待队列上的线程;
互斥
多线程对临界资源访问的安全性;
互斥锁实现互斥:通过加锁解锁操作保证同一时刻只有一个线程对临界资源进行操作;
信号量实现同步:使用0/1标记,信号量为0时,有其他线程在操作资源,阻塞;信号量为1时,可访问操作;
信号量操作
#include <semaphore.h>
//初始化无名信号量
int sem_init(sem_t *sem, int pshared, unsigned int value); //Link with -pthread.
//sem:指向无名信号量地址的指针
//pshared:表示信号量是在线程/进程中使用;0为线程;1为进程
//value:信号量的初始值
//阻塞信号量 //Link with -pthread.
int sem_wait(sem_t *sem);
int sem_trywait(sem_t *sem);
int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);
//sem:信号量指针
//自带判断功能:>0,信号量计数-1,立即返回;=0,阻塞
//sem_trywait:功能于sem_wait相同,但不阻塞如果不能立即返回则返回一个错误errno(EAGAIN);
//abs_timeout:一个结构体表示阻塞事件
//sem_timedwait:如果不能立即返回则调用阻塞时间量,如果时间阻塞量过期,则返回一个错误errno(ETIMEDOUT);
//解锁信号量
int sem_post(sem_t *sem); //Link with -pthread.
//sem指向的信号量计数+1,如果信号量大于0,则唤醒阻塞线程
//销毁信号量
int sem_destroy(sem_t *sem); //Link with -pthread.
使用信号量实现生产者消费者模型
#include<iostream>
#include<thread>
#include<semaphore.h>
#include<vector>
#define MAXQ 4 //定义资源上限
using namespace std;
class RingQueue{
public:
RingQueue(int maxq = MAXQ)
:_capacity(maxq)
,_queue(maxq)
{
sem_init(&_lock,0,1); //初始值为1
sem_init(&_idle_space,0,_capacity); //空闲位置的个数
sem_init(&_data_space,0,0);
}
~RingQueue()
{
sem_destroy(&_lock);
sem_destroy(&_idle_space);
sem_destroy(&_data_space);
}
bool QueuePush(int data)
{
sem_wait(&_idle_space); //判断是否有空闲位置,若=0,则等待
sem_wait(&_lock); //加锁
_queue[_write] = data;
_write =(_write+1)%_capacity;
sem_post(&_lock);
sem_post(&_data_space);
return true;
}
bool QueuePop(int& data)
{
sem_wait(&_data_space);
sem_wait(&_lock);
data = _queue[_read];
_read = (_read + 1)%_capacity;
sem_post(&_lock);
sem_post(&_idle_space);
return true;
}
private:
vector<int> _queue; //环形队列
int _capacity;
int _write; //写入标记
int _read; //读取标记
sem_t _lock; //实现互斥锁
sem_t _idle_space; //空闲空间
sem_t _data_space; //数据量
};
void thr_con(RingQueue* q) //消费者
{
int data = 0;
while(1)
{
q->QueuePop(data);
cout<<"thr_con : "<<data<<endl;
}
return ;
}
int data =0;
void thr_pro(RingQueue* q) //生产者
{
while(1)
{
q->QueuePush(data);
cout<<"thr_pro"<<data++<<endl;
}
return ;
}
int main()
{
RingQueue q; //环形队列
vector<thread> list_con(4); //消费者线程
vector<thread> list_pro(4); //生产者线程
for(int i =0; i<4; i++)
{
list_con[i] = thread(thr_con,&q);
}
for(int i=0; i<4; i++)
{
list_pro[i] = thread(thr_pro,&q);
}
//回收线程
for(int i=0; i<4; i++)
{
list_con[i].join();
list_pro[i].join();
}
return 0;
}