Linux信号量:POSIX标准接口、实现生产者与消费者模型

简介: Linux信号量:POSIX标准接口、实现生产者与消费者模型

一、信号量简介


1.信号量


本质:内核中的一个计数器+等待队列


操作:PV操作


       P操作:判断计数器:


               大于0,则返回,返回前计数器-1;


               小于等于0则阻塞。


       V操作:计数器计数+1,唤醒一个阻塞的执行流


作用:实现进程或线程间的同步与互斥


       同步实现:计数器对资源进行计数


               获取资源前,进行P操作;


               产生一个资源,进行V操作;


       互斥实现:计数器置1,表示资源只有一个


               访问资源前,进行P操作;


               访问资源完毕后,进行V操作。


2.信号量与条件变量的区别


相同点:


       信号量与条件变量都可以实现同步


区别:


       信号量本身带有计数器,自身提供了资源获取条件判断的功能;


       条件变量,条件判断需要用户自己实现。


二、信号量标准接口POSIX


1.定义信号量


sem_t;


2.初始化信号量


int sem_init(sem_t *sem, int pshared, int val);


       sem:信号量变量;


       pshared: 0用于线程间;非0用于进程间;


       val:信号量的初始值;


返回值:


       成功,返回0;失败,返回-1。


3.P操作


int sem_wait(sem_t *sem);阻塞
int sem_trywait(sem_t *sem);非阻塞
int sem_timedwait(sem_t *sem);有时长限制的阻塞。


4.V操作


int sem_post(sem_t *sem);


5.释放信号量


int sem_destroy(sem_t *sem);


三、信号量实现生产者与消费者模型


1.信号量实现线程安全的环形队列


template <class T>
class CircularQueue {
    pricate:
        //实现环形队列
        std::vector<T> _array;
        int _capacity;
        int _front = 0;
        int _rear = 0;
        //实现同步
        sem_t _sem_idle;//对队列空闲空间计数
        sem_t _sem_data;//对有效数据节点计数
        //实现互斥
        sem_t _sem_lock;//实现互斥锁
};


2.完整代码


#include<iostream>
#include<cstdlib>
#include<vector>
#include<semaphore.h>
#include<pthread.h>
#define MAX_QUEUE 5
#define PRODUCER 4
#define CONSUMER 4
template <class T>
class CircularQueue {
  private:
    std::vector<T> _array;
    int _front;
    int _rear;
    int _capacity;
    sem_t _sem_idle;//对空闲空间计数
    sem_t _sem_data;//对数据空间计数
    sem_t _sem_lock;//实现互斥锁
  public:
    CircularQueue(int cap = MAX_QUEUE)
      : _capacity(cap) 
      ,_front(0)
      ,_rear(0)
      ,_array(cap) 
  {
    sem_init(&_sem_idle, 0, cap);
    sem_init(&_sem_data, 0, 0);
    sem_init(&_sem_lock, 0, 1);
  }
    ~CircularQueue() {
      sem_destroy(&_sem_idle);
      sem_destroy(&_sem_data);
      sem_destroy(&_sem_lock);
   }
    bool Push(const T data) {
     //1.P操作,对空闲空间计数进行判断
     sem_wait(&_sem_idle);
     //2.获取锁
     sem_wait(&_sem_lock);
     //3.放入数据
     _array[_front] = data;
     _front = (_front + 1) % _capacity;
     //4.解锁
     sem_post(&_sem_lock);
     //5.V操作,对数据空间进行计数+1
     sem_post(&_sem_data);
    }
    bool Pop(T *data) {
      //1.P操作,对数据空间计数进行判断
      sem_wait(&_sem_data); 
      //2.获取锁
      sem_wait(&_sem_lock);
      //3.获取数据
      *data = _array[_rear];
      _rear = (_rear + 1) % _capacity;
      //4.解锁
      sem_post(&_sem_lock);
      //5.V操作,对空闲空间计数+1
      sem_post(&_sem_idle);
    }
};
void *Consumer(void *arg) {
  CircularQueue<int> *p = (CircularQueue<int>*)arg;
  while (1) {
    int data;
    p -> Pop(&data);
    printf("Consumer get data: %d\n", data);
  }
}
void *Producer(void *arg) {
  CircularQueue<int> *p = (CircularQueue<int>*)arg;
  int data = 1;
  while (1) {
    p -> Push(data);
    printf("Producer put data: %d\n", data);
    ++data;
  }
}
void Test() {
  int ret;
  pthread_t con_tid[CONSUMER], pro_tid[PRODUCER];
  CircularQueue<int> q;
  //Create consumer threads 
  for (int i = 0; i < CONSUMER;  ++i) {
    pthread_create(&con_tid[i], NULL, Consumer, (void*)&q);
    if (ret != 0) {
      std::cout<<"Create consumer threads error!"<<std::endl;
      return;
    }
  }
  //Create producer threads 
  for (int i = 0; i < PRODUCER;  ++i) {
    pthread_create(&pro_tid[i], NULL, Producer, (void*)&q);
    if (ret != 0) {
      std::cout<<"Create producer threads error!"<<std::endl;
      return ;
    }
  }
  //wait threads 
  for (int i = 0; i < CONSUMER; ++i) {
    pthread_join(con_tid[i], NULL);
  }
  for (int i = 0; i < PRODUCER; ++i) {
    pthread_join(pro_tid[i], NULL);
  }
}
int main () {
  Test();
  return 0;
}


实现效果:


1.png

相关文章
|
2天前
|
缓存 网络协议 算法
【Linux系统编程】深入剖析:四大IO模型机制与应用(阻塞、非阻塞、多路复用、信号驱动IO 全解读)
在Linux环境下,主要存在四种IO模型,它们分别是阻塞IO(Blocking IO)、非阻塞IO(Non-blocking IO)、IO多路复用(I/O Multiplexing)和异步IO(Asynchronous IO)。下面我将逐一介绍这些模型的定义:
|
2天前
|
Linux 网络安全 虚拟化
Ngnix04系统环境准备-上面软件是免费版的,下面是收费版的,他更快的原因使用了epoll模型,查看当前Linux系统版本, uname -a,VMWARE建议使用NAT,PC端电脑必须使用网线连接
Ngnix04系统环境准备-上面软件是免费版的,下面是收费版的,他更快的原因使用了epoll模型,查看当前Linux系统版本, uname -a,VMWARE建议使用NAT,PC端电脑必须使用网线连接
|
2天前
|
Linux 调度
部署02-我们一般接触的是Mos和Wimdows这两款操作系统,很少接触到Linux,操作系统的概述,硬件是由计算机系统中由电子和机械,光电元件所组成的,CPU,内存,硬盘,软件是用户与计算机接口之间
部署02-我们一般接触的是Mos和Wimdows这两款操作系统,很少接触到Linux,操作系统的概述,硬件是由计算机系统中由电子和机械,光电元件所组成的,CPU,内存,硬盘,软件是用户与计算机接口之间
|
11天前
|
安全 Linux 数据安全/隐私保护
【linux】线程同步和生产消费者模型
【linux】线程同步和生产消费者模型
10 0
|
Linux
Linux IPC实践(10) --Posix共享内存
1. 创建/获取一个共享内存 #include #include /* For mode constants */ #include /* For O...
871 0
|
2天前
|
Linux 网络安全 开发工具
linux 常用命令【编程必备】
linux 常用命令【编程必备】
14 4
|
2天前
|
存储 Linux
Linux文件的上和下,FinalShell文件右键可下文件,先选择root文件夹,然后把他文件往里面拖动,就可以下载了,命令下载,ls -l可以看当前文件目录,sz 文件名可下载,tab补,rz出上
Linux文件的上和下,FinalShell文件右键可下文件,先选择root文件夹,然后把他文件往里面拖动,就可以下载了,命令下载,ls -l可以看当前文件目录,sz 文件名可下载,tab补,rz出上
|
2天前
|
安全 Linux 测试技术
Linux命令setpriv详解
`setpriv` 是Linux下的命令行工具,用于调整进程权限以增强安全性,尤其适用于自动化和非交互式权限切换。它不使用PAM,支持管理能力集、GID/UID及SELinux上下文。例如,`setpriv --reuid=1000 script.sh` 可以以低权限用户运行脚本,而`--selinux-label`可设定SELinux标签。在使用时,应最小化权限、充分测试、保持与其他安全机制的兼容性,并定期审核权限设置。
|
2天前
|
Linux 数据安全/隐私保护
Linux命令setfacl详解
`setfacl`是Linux中用于设置文件访问控制列表的命令,提供比传统权限更细粒度的控制。它允许为特定用户或组添加、修改或删除权限,适用于多用户环境和复杂场景。常用参数包括`-m`(修改规则)、`-x`(删除规则)、`-R`(递归设置)和`-d`(设置默认ACL)。例如,`setfacl -m u:user1:rw- file.txt`给用户`user1`赋予文件`file.txt`的读写权限。记得在使用前确认文件系统支持ACL,并谨慎规划和审查权限设置。
|
2天前
|
Linux 数据处理
Linux命令setarch深度解析与实际应用
`setarch`是Linux下用于调整程序执行环境的命令,它允许在不同CPU架构间运行二进制文件,模拟架构并设置CPU功能标志。通过指定`-a`参数切换架构,如`-a i386`,用`-R`参数启用或禁用如SSE2的功能。在测试兼容性、调试和优化时非常有用。注意正确设置参数,避免滥用,确保程序正常运行。查阅文档、逐步测试和考虑兼容性是最佳实践。