【Linux系统编程】用互斥量和信号量加锁STL容器,避免并发问题

目录

引言

容器模型

容器代码


个人主页:东洛的克莱斯韦克-CSDN博客

引言

STL容器并没有保证线程安全,而大多数应用场景下,为了追求效率,多线程是必不可少的。而底层容器难免会有并发问题。从设计上来说要么在上层代码做加锁处理,要么封装出能保证线程安全容器。

本文给出的方案是用信号量和互斥量封装vector容器------用两个信号量和两个互斥量封装出环形队列。

容器模型

给容器设计两个接口,push()用来向容器填充数据,pop用来向容器取数据。调用push接口的称为生产者,调用pop接口的称为消费者。

vector容器用下标回绕的方式,在逻辑上是一个环形。线程先去申请信号量资源,申请到了信号量资源的线程再去竞争互斥量,谁能锁住互斥量,谁就去容器里操作。

有了信号量和互斥量的存在,在任意时刻,有且只能有0或1个生产者,0或1个消费者线程在容器里操作。那么push接口和pop接口就是原子性的操作。

容器代码

cpp 复制代码
#pragma once // 防止头文件被重复包含
//保证线程安全的环形队列容器
#include <vector>
#include <semaphore.h>
#include <pthread.h>
 
 #define C_MAX 300 //容器的容量

template <class T>
class annular
{
 
public:
    annular(int max_c = C_MAX)
        : max_capacity(max_c), min_capacity(0), _c_subscript(0), _p_subscript(0)
    {
        _v.reserve(max_c);
      
        pthread_mutex_init(&_c_lock, nullptr);
        pthread_mutex_init(&_p_lock, nullptr);
        sem_init(&_c_sem, 0, 0);
        sem_init(&_p_sem, 0, max_c);
    }
 
    ~annular()
    {
        pthread_mutex_destroy(&_c_lock);
        pthread_mutex_destroy(&_p_lock);
        sem_destroy(&_c_sem);
        sem_destroy(&_p_sem);
    }
 
    void push(const T &data)
    {
        sem_wait(&_p_sem);            // 信号量的p操作
        pthread_mutex_lock(&_p_lock); // 加锁
 
        _v[_p_subscript] = data;
        _p_subscript++;
        _p_subscript %= max_capacity;
 
        sem_post(&_c_sem);              // 信号量的v操作
        pthread_mutex_unlock(&_p_lock); // 解锁
    }
 
    void pop(T &data)
    {
        sem_wait(&_c_sem);            // 信号量的p操作
        pthread_mutex_lock(&_c_lock); // 加锁
 
        data = _v[_c_subscript];
        _c_subscript++;
        _c_subscript %= max_capacity;
 
        sem_post(&_p_sem);              // 信号量的v操作
        pthread_mutex_unlock(&_c_lock); // 解锁
    }
 
private:
    pthread_mutex_t _c_lock; // 消费者互斥量
    pthread_mutex_t _p_lock; // 生产者互斥量
    sem_t _c_sem;            // 消费者信号量
    sem_t _p_sem;            // 生产者信号量
    int _c_subscript;        // 消费者下标
    int _p_subscript;        // 生产者下标
    std::vector<T> _v;
    int max_capacity; // 容器最大容量
    int min_capacity; // 容器最小容量
};
相关推荐
W23035765738 小时前
经典算法:最长上升子序列(LIS)深度解析 C++ 实现
开发语言·c++·算法
.Ashy.8 小时前
2026.4.11 蓝桥杯软件类C/C++ G组山东省赛 小记
c语言·c++·蓝桥杯
minji...9 小时前
Linux 线程同步与互斥(三) 生产者消费者模型,基于阻塞队列的生产者消费者模型的代码实现
linux·运维·服务器·开发语言·网络·c++·算法
CoderCodingNo11 小时前
【GESP】C++三级真题 luogu-B4499, [GESP202603 三级] 二进制回文串
数据结构·c++·算法
hetao173383712 小时前
2026-04-09~12 hetao1733837 的刷题记录
c++·算法
6Hzlia12 小时前
【Hot 100 刷题计划】 LeetCode 136. 只出现一次的数字 | C++ 哈希表&异或基础解法
c++·算法·leetcode
汉克老师13 小时前
GESP2024年6月认证C++三级( 第二部分判断题(1-10))
c++·数组·位运算·补码·gesp三级·gesp3级
无限进步_14 小时前
【C++】只出现一次的数字 II:位运算的三种解法深度解析
数据结构·c++·ide·windows·git·算法·leetcode
小贾要学习14 小时前
【Linux】TCP网络通信编程
linux·服务器·网络·c++·网络协议·tcp/ip
哎嗨人生公众号15 小时前
手写求导公式,让轨迹优化性能飞升,150ms变成9ms
开发语言·c++·算法·机器人·自动驾驶