信号量Semaphore

server/2024/9/25 17:11:40/

什么是信号量?

C++中的信号量(Semaphore)是一种同步对象,用于控制对共享资源的访问,以防止多个线程或进程同时访问同一资源,从而避免数据不一致的问题。信号量通过维护一个计数值来实现这一功能,该计数值表示可以同时访问共享资源的线程或进程的数量。当一个线程或进程想要访问共享资源时,它会尝试减少信号量的计数值;如果计数值大于零,线程或进程可以继续执行,否则它必须等待直到信号量的计数值变为正数。当线程或进程完成对共享资源的访问后,它会释放信号量,即增加计数值,从而可能允许其他正在等待的线程或进程继续执行。

信号量可以干什么?

  1. 互斥
  2. 限制并发访问
  3. 线程同步
#include <iostream>
#include <thread>
#include <vector>
#include <mutex>
#include <condition_variable>class Semaphore {
public:Semaphore(int count = 1) : count_(count) {}void notify() {std::unique_lock<std::mutex> lock(mutex_);++count_;condition_.notify_one();}void wait() {std::unique_lock<std::mutex> lock(mutex_);while (count_ <= 0) {condition_.wait(lock);}--count_;}private:std::mutex mutex_;std::condition_variable condition_;int count_;
};// 共享资源
int sharedResource = 0;void workerFunction(Semaphore& semaphore) {for (int i = 0; i < 1000; ++i) {semaphore.wait(); // 加锁++sharedResource;semaphore.notify(); // 解锁}
}//实现互斥int main() {Semaphore semaphore(1);std::vector<std::thread> threads;// 创建 10 个工作线程for (int i = 0; i < 10; ++i) {threads.push_back(std::thread(workerFunction, std::ref(semaphore)));}// 等待所有线程完成for (auto& thread : threads) {thread.join();}std::cout << "Shared resource value: " << sharedResource << std::endl;return 0;
}
#include <iostream>
#include <thread>
#include <vector>
#include <chrono>
#include <mutex>
#include <condition_variable>class Semaphore {
public:Semaphore(int count = 1) : count_(count) {}void notify() {std::unique_lock<std::mutex> lock(mutex_);++count_;condition_.notify_one();}void wait() {std::unique_lock<std::mutex> lock(mutex_);while (count_ <= 0) {condition_.wait(lock);}--count_;}private:std::mutex mutex_;std::condition_variable condition_;int count_;
};void workerFunction(int threadId, Semaphore& semaphore) {semaphore.wait(); // 获取访问权限std::cout << "Thread " << threadId << " is accessing the shared resource." << std::endl;// 模拟访问共享资源std::this_thread::sleep_for(std::chrono::seconds(1));std::cout << "Thread " << threadId << " has finished accessing the shared resource." << std::endl;semaphore.notify(); // 释放访问权限
}//限制并发访问int main() {Semaphore semaphore(3); // 允许最多3个线程同时访问std::vector<std::thread> threads;// 创建10个工作线程for (int i = 0; i < 10; ++i) {threads.push_back(std::thread(workerFunction, i, std::ref(semaphore)));}// 等待所有线程完成for (auto& thread : threads) {thread.join();}return 0;
}
#include <iostream>
#include <thread>
#include <vector>
#include <mutex>
#include <condition_variable>class Semaphore {
public:Semaphore(int count = 1) : count_(count) {}void notify() {std::unique_lock<std::mutex> lock(mutex_);++count_;condition_.notify_one();}void wait() {std::unique_lock<std::mutex> lock(mutex_);while (count_ <= 0) {condition_.wait(lock);}--count_;}private:std::mutex mutex_;std::condition_variable condition_;int count_;
};void task1(Semaphore& semaphore1, Semaphore& semaphore2) {std::cout << "Task 1 is executing." << std::endl;// 模拟任务执行std::this_thread::sleep_for(std::chrono::seconds(1));std::cout << "Task 1 is completed." << std::endl;// 通知任务2可以开始执行semaphore1.notify();// 等待任务2完成// semaphore2.wait();
}void task2(Semaphore& semaphore1, Semaphore& semaphore2) {// 等待任务1完成semaphore1.wait();std::cout << "Task 2 is executing." << std::endl;// 模拟任务执行std::this_thread::sleep_for(std::chrono::seconds(1));std::cout << "Task 2 is completed." << std::endl;// 通知任务3可以开始执行semaphore2.notify();
}void task3(Semaphore& semaphore2) {// 等待任务2完成semaphore2.wait();std::cout << "Task 3 is executing." << std::endl;// 模拟任务执行std::this_thread::sleep_for(std::chrono::seconds(1));std::cout << "Task 3 is completed." << std::endl;
}//线程同步int main() {Semaphore semaphore1(0), semaphore2(0);std::thread t1(task1, std::ref(semaphore1), std::ref(semaphore2));std::thread t2(task2, std::ref(semaphore1), std::ref(semaphore2));std::thread t3(task3, std::ref(semaphore2));t1.join();t2.join();t3.join();return 0;
}

信号量怎么实现?

C++11

使用互斥锁和条件变量模拟信号量。

#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <vector>class Semaphore {
public:Semaphore(int count) : _count(count) {}void acquire() {std::unique_lock<std::mutex> lock(_mutex);while (_count == 0) {_cv.wait(lock);}--_count;}void release() {std::lock_guard<std::mutex> lock(_mutex);++_count;_cv.notify_one();}private:int _count;std::mutex _mutex;std::condition_variable _cv;
};Semaphore taskSemaphore(4); // 最大并发数为4void processTask(int taskID) {taskSemaphore.acquire();std::cout << "Task " << taskID << " started." << std::endl;std::this_thread::sleep_for(std::chrono::seconds(10));std::cout << "Task " << taskID << " finished." << std::endl;taskSemaphore.release();
}int main() {std::vector<std::thread> threads;const int numTasks = 10;for (int i = 1; i <= numTasks; ++i) {threads.emplace_back(processTask, i);}for (auto& thread : threads) {thread.join();}return 0;
}

C++20

使用std::counting_semaphore

#include <iostream>
#include <thread>
#include <semaphore>
#include <vector>// 假设我们有一个最大并发数为4的任务队列
std::counting_semaphore<4> taskSemaphore(4);void processTask(int taskID) {// 请求一个任务许可taskSemaphore.acquire();std::cout << "Task " << taskID << " started." << std::endl;// 这里模拟任务处理时间std::this_thread::sleep_for(std::chrono::milliseconds(10000));std::cout << "Task " << taskID << " finished." << std::endl;// 任务处理完释放许可taskSemaphore.release();
}int main() {std::vector<std::thread> threads;const int numTasks = 10;for (int i = 1; i <= numTasks; ++i) {threads.emplace_back(processTask, i);}for (auto& thread : threads) {thread.join();}return 0;
}

经典生产者消费者问题

#include <iostream>
#include <thread>
#include <vector>
#include <queue>
#include <chrono>
#include <mutex>
#include <condition_variable>class Semaphore {
public:Semaphore(int count = 1) : count_(count) {}void notify() {std::unique_lock<std::mutex> lock(mutex_);++count_;condition_.notify_one();}void wait() {std::unique_lock<std::mutex> lock(mutex_);while (count_ <= 0) {condition_.wait(lock);}--count_;}private:std::mutex mutex_;std::condition_variable condition_;int count_;
};const int BUFFER_SIZE = 10;
std::queue<int> buffer;
std::mutex mutex_; // 互斥锁,用于保护共享数据
Semaphore empty(BUFFER_SIZE), full(0);void producer(int producerId) {for (int i = 0; i < 100; ++i) {empty.wait(); // 等待缓冲区有空位std::unique_lock<std::mutex> lock(mutex_);buffer.push(i);std::cout << "Producer " << producerId << " produced: " << i << std::endl;lock.unlock();full.notify(); // 通知消费者有新数据}
}void consumer(int consumerId) {for (int i = 0; i < 100; ++i) {full.wait(); // 等待缓冲区有数据std::unique_lock<std::mutex> lock(mutex_);int data = buffer.front();buffer.pop();std::cout << "Consumer " << consumerId << " consumed: " << data << std::endl;lock.unlock();empty.notify(); // 通知生产者有空位}
}int main() {std::vector<std::thread> producers, consumers;// 创建3个生产者线程for (int i = 0; i < 3; ++i) {producers.push_back(std::thread(producer, i));}// 创建3个消费者线程for (int i = 0; i < 3; ++i) {consumers.push_back(std::thread(consumer, i));}// 等待所有生产者线程完成for (auto& producer : producers) {producer.join();}// 等待所有消费者线程完成for (auto& consumer : consumers) {consumer.join();}return 0;
}


http://www.ppmy.cn/server/18303.html

相关文章

vue整合Echarts

首先打开网址https://echarts.apache.org/examples/zh/index.html 进入Echars官网找到自己想要的图形我这里选择的是柱形图 点开完整代码直接cv大法 下载Echars的npm npm install echarts 在vue里面挂在个div 导入相关包 写个方法 就是cv过来的 然后改成后端传过来的值…

【网络原理】TCP协议的连接管理机制(三次握手和四次挥手)

系列文章目录 【网络通信基础】网络中的常见基本概念 【网络编程】网络编程中的基本概念及Java实现UDP、TCP客户端服务器程序&#xff08;万字博文&#xff09; 【网络原理】UDP协议的报文结构 及 校验和字段的错误检测机制&#xff08;CRC算法、MD5算法&#xff09; 【网络…

C# - 反射获取字段/属性/方法

using System; using System.Reflection;public class MyClass {public int MyField;public int MyProperty { get; set; }public void MyMethod() { } }class Program {static void Main(){Type type typeof(MyClass);// 获取字段FieldInfo fieldInfo type.GetField("M…

Qt Android 申请写文件到内部存储

问题描述 在项目中我们有一个软件配置文件&#xff0c;在软件更新一些配置后需要将配置信息保存到配置文件中&#xff0c;Windows 下是将配置文件保存到软件当前目录下&#xff0c;但是 Android 环境下无法保存到程序当前目录&#xff0c;最终只能将配置文件保存到内部存储中&…

VBA之Word应用第二章第五节:将光标转到指定书签位置

《VBA之Word应用》&#xff08;版权10178982&#xff09;&#xff0c;是我推出第八套教程&#xff0c;教程是专门讲解VBA在Word中的应用&#xff0c;围绕“面向对象编程”讲解&#xff0c;首先让大家认识Word中VBA的对象&#xff0c;以及对象的属性、方法&#xff0c;然后通过实…

uniapp获取当前经纬度、地图逆地址解析

该功能可用于移动端&#xff0c;官网&#xff1a;uni.getLocation(OBJECT) | uni-app官网 uni.getLocation({type: gcj02, // 坐标类型&#xff0c;默认为wgs84&#xff0c;可选的值为gcj02和bd09ll// isHighAccuracy:true,success: res > {// 获取成功&#xff0c;经度和纬…

php时间人性化展示

在PHP中,可以使用date()函数和strtotime()函数来实现时间的人性化展示。下面是一个示例代码: <?php // 获取当前时间戳 $timestamp = time();// 格式化时间 $formattedTime = date(Y年m月d日 H:i:s, $timestamp);echo

大小写不规范引起的LVS问题

我正在「拾陆楼」和朋友们讨论有趣的话题,你⼀起来吧? 拾陆楼知识星球入口 往期文章链接: LVS常见问题解析 综合网表不规范,大小写混用常导致LVS问题,比如两个端口clk和CLK只有大小写区别,PR工具是可以识别为两个端口的,只不过Calibre LVS默认不区分大小写,会报错。 …