Linux信号量的理解和使用

信号量

信号量是一个计数器,可用于实现多线程和多进程之间的临界资源访问安全和合理性,即同步与互斥;
    这里我主要实现的是线程间的同步与互斥;
信号量分类
信号量可分为:内核信号量和用户信号量
      内核信号量:由内核控制路径使用
      用户信号量:用户态进程使用的信号量;分为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;
}

在这里插入图片描述

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值