当前位置: 首页 > news >正文

C++17 信号量模拟实现

C++17 信号量模拟实现

一、实现原理

C++17 标准库没有原生信号量(C++20才有),但可以通过 std::mutex + std::condition_variable 模拟实现。以下是核心逻辑:

#include <mutex>
#include <condition_variable>class CountingSemaphore {
private:int count_;                  // 当前可用资源数std::mutex mutex_;           // 保护计数器的锁std::condition_variable cv_; // 阻塞/唤醒线程public:explicit CountingSemaphore(int initial = 0) : count_(initial) {}// P操作:请求资源(计数器减1)void acquire() {std::unique_lock<std::mutex> lock(mutex_);cv_.wait(lock, [this] { return count_ > 0; }); // 等待资源可用--count_;}// V操作:释放资源(计数器加1)void release() {std::lock_guard<std::mutex> lock(mutex_);++count_;cv_.notify_one(); // 唤醒一个等待线程}
};
二、完整可编译代码
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <queue>
#include <chrono>// 信号量实现类
class CountingSemaphore {
private:int count_;std::mutex mutex_;std::condition_variable cv_;
public:explicit CountingSemaphore(int initial = 0) : count_(initial) {}void acquire() {std::unique_lock<std::mutex> lock(mutex_);cv_.wait(lock, [this] { return count_ > 0; });--count_;}void release() {std::lock_guard<std::mutex> lock(mutex_);++count_;cv_.notify_one();}
};// 全局资源
constexpr int MAX_BUFFER = 5;
CountingSemaphore empty_slots(MAX_BUFFER); // 初始空位
CountingSemaphore data_items(0);           // 初始数据项
std::mutex buffer_mutex;                   // 保护缓冲区
std::queue<int> buffer;                     // 共享缓冲区
bool producer_done = false;                // 生产结束标志// 生产者函数
void producer() {for (int i = 1; i <= 10; ++i) {empty_slots.acquire(); // 等待空位{std::lock_guard<std::mutex> lock(buffer_mutex);buffer.push(i);std::cout << "生产者添加: " << i << std::endl;}data_items.release(); // 增加数据项std::this_thread::sleep_for(std::chrono::milliseconds(100));}// 标记生产完成std::lock_guard<std::mutex> lock(buffer_mutex);producer_done = true;
}// 消费者函数
void consumer() {while (true) {data_items.acquire(); // 等待数据项{std::lock_guard<std::mutex> lock(buffer_mutex);if (producer_done && buffer.empty()) break; // 退出条件int val = buffer.front();buffer.pop();std::cout << "消费者取出: " << val << std::endl;}empty_slots.release(); // 释放空位std::this_thread::sleep_for(std::chrono::milliseconds(150));}
}int main() {std::thread t1(producer);std::thread t2(consumer);t1.join();t2.join();std::cout << "程序正常退出" << std::endl;return 0;
}
三、编译与运行
  1. 编译命令(需要支持C++17的编译器):

    g++ -std=c++17 -pthread -o semaphore_demo semaphore_demo.cpp
    
  2. 运行输出示例

四、关键机制解析
组件作用
std::mutex保护共享计数器 count_ 的线程安全访问
std::condition_variable实现阻塞等待和唤醒机制
cv_.wait()阻塞线程直到资源可用(count_ > 0
cv_.notify_one()资源释放后唤醒一个等待线程
五、注意事项
  1. 虚假唤醒处理cv_.wait() 必须使用循环判断条件

    cv_.wait(lock, [this] { return count_ > 0; }); // 正确写法
    
  2. 死锁避免:确保每次 acquire() 都有对应的 release()

  3. 性能优化:高频场景下可改用 notify_all() + 线程竞争

    void release() {std::lock_guard<std::mutex> lock(mutex_);++count_;cv_.notify_all(); // 唤醒所有线程
    }
    

C语言的信号量

#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>sem_t sem;
int shared_counter = 0;void* thread_func(void* arg) {for (int i = 0; i < 100000; i++) {sem_wait(&sem);       // P操作shared_counter++;     // 临界区sem_post(&sem);       // V操作}return NULL;
}int main() {// 初始化信号量(初始值为1)if (sem_init(&sem, 0, 1) != 0) {perror("sem_init failed");return 1;}pthread_t t1, t2;// 创建线程1if (pthread_create(&t1, NULL, thread_func, NULL) != 0) {perror("pthread_create t1 failed");return 1;}// 创建线程2if (pthread_create(&t2, NULL, thread_func, NULL) != 0) {perror("pthread_create t2 failed");return 1;}// 等待线程结束pthread_join(t1, NULL);pthread_join(t2, NULL);printf("Final counter value: %d\n", shared_counter);  // 正确应为200000// 销毁信号量sem_destroy(&sem);return 0;
}

http://www.mrgr.cn/news/98981.html

相关文章:

  • 文件上传Ⅰ
  • leetcode第20题(有效的括号)
  • FreeRTOS任务通知
  • MDA测量数据查看器【内含工具和源码地址】
  • Qt QTimer 详解与使用指南
  • 力扣刷题Day 20:柱状图中最大的矩形(84)
  • 解锁C++ gRPC:快速入门指南
  • Java集合框架深度解析:HashMap、HashSet、TreeMap、TreeSet与哈希表原理详解
  • Json 在线格式化 - 加菲工具
  • 工厂方法模式详解及在自动驾驶场景代码示例(c++代码实现)
  • 【多目标进化算法】NSGA-II 算法(结合例子)
  • 2048小游戏C++板来啦!
  • MATLAB 控制系统设计与仿真 - 36
  • 论文阅读:2023 ICLR Safe RLHF: Safe Reinforcement Learning from Human Feedback
  • C++智能指针的知识!
  • 阿里云服务器搭建开源版禅道
  • Web三漏洞学习(其三:rce漏洞)
  • java线程池原理及使用和处理流程
  • 算法-链表
  • 基于autoware1.14的实车部署激光雷达循迹,从建图、定位、录制轨迹巡航点、到实车运行。