C++笔记之信号量、互斥量与PV操作

news2024/11/21 0:24:22

C++笔记之信号量、互斥量与PV操作

文章目录

  • C++笔记之信号量、互斥量与PV操作
    • 1.信号量概念
    • 2.信号量例程一
    • 3.信号量例程二
    • 4.信号量例程三
    • 5.互斥量
    • 6.PV操作概念
    • 7.PV操作详解——抄自:https://mp.weixin.qq.com/s/vvjhbzsWQNRkU7-b_dURlQ

1.信号量概念

C++中的信号量是一种同步原语,用于在多线程或多进程环境中管理资源的访问和控制并发访问的方式。信号量主要用于协调不同线程或进程之间对共享资源的访问,以确保互斥性和同步性。

信号量有两种常见的类型:二进制信号量和计数信号量。

  1. 二进制信号量(Binary Semaphore):也称为互斥锁(Mutex),它只能取两个值,通常是0和1。它用于实现互斥访问,即同一时间只允许一个线程或进程访问共享资源。当一个线程或进程获得了二进制信号量,其他尝试获取的线程或进程将被阻塞,直到信号量被释放。

  2. 计数信号量(Counting Semaphore):计数信号量可以取多个值,通常是非负整数。它用于控制同时访问共享资源的数量,允许多个线程或进程访问资源,但可以限制并发访问的数量。线程或进程可以等待信号量的计数增加,以获得访问权限,或者通过释放信号量来减少计数。

信号量通常具有两个主要操作:

  • Wait(等待)操作:线程或进程尝试获取信号量。如果信号量的计数不满足要求(例如,计数为0),则线程或进程将被阻塞,直到条件满足。
  • Signal(通知)操作:线程或进程释放信号量,增加计数。这通常是在使用完共享资源后执行的操作,以通知其他等待的线程或进程。

信号量是多线程和多进程编程中重要的同步工具,用于避免竞态条件和确保数据的一致性。在C++中,你可以使用标准库提供的互斥锁、条件变量以及其他同步原语来实现信号量,或者使用第三方库中提供的信号量实现,如Boost C++库中的信号量。

2.信号量例程一

在这里插入图片描述

运行
在这里插入图片描述

代码

#include <condition_variable>
#include <iostream>
#include <mutex>
#include <thread>

class Semaphore {
  public:
    Semaphore(int count = 0) : count_(count) {}

    void notify() {
        std::unique_lock<std::mutex> lock(mutex_);
        count_++;
        cv_.notify_one();
    }

    void wait() {
        std::unique_lock<std::mutex> lock(mutex_);
        while (count_ == 0) {
            cv_.wait(lock);
        }
        count_--;
    }

  private:
    std::mutex mutex_;
    std::condition_variable cv_;
    int count_;
};

int main() {
    Semaphore semaphore(0); // 创建一个初始计数为3的信号量

    std::thread t1([&semaphore]() {
        semaphore.wait();
        std::cout << "Thread 1 is running." << std::endl;
    });

    std::thread t2([&semaphore]() {
        semaphore.wait();
        std::cout << "Thread 2 is running." << std::endl;
    });

    semaphore.notify(); // 释放一个许可
    std::this_thread::sleep_for(std::chrono::seconds(1));
    std::cout << " 让主线程等待一会儿..." << std::endl;
    semaphore.notify(); // 释放一个许可

    t1.join();
    t2.join();

    return 0;
}

3.信号量例程二

在这里插入图片描述

运行
在这里插入图片描述

代码

#include <condition_variable>
#include <iostream>
#include <mutex>
#include <thread>

class Semaphore {
  public:
    Semaphore(int count = 0) : count_(count) {}

    void notify() {
        std::unique_lock<std::mutex> lock(mutex_);
        count_++;
        cv_.notify_one();
    }

    void wait() {
        std::unique_lock<std::mutex> lock(mutex_);
        while (count_ == 0) {
            cv_.wait(lock);
        }
        count_--;
    }

  private:
    std::mutex mutex_;
    std::condition_variable cv_;
    int count_;
};

Semaphore sem(0); // 创建一个初始计数为0的信号量

void worker(int id) {
    std::cout << "Thread " << id << " is waiting." << std::endl;
    sem.wait();
    std::cout << "Thread " << id << " has acquired the semaphore." << std::endl;
    // 这里可以执行需要互斥访问的代码
}

int main() {
    std::thread t1(worker, 1);
    std::thread t2(worker, 2);

    std::this_thread::sleep_for(std::chrono::seconds(2)); // 让主线程等待一会儿

    std::cout << "Main thread is notifying the semaphore." << std::endl;
    sem.notify(); // 释放一个许可

    t1.join();
    t2.join();

    return 0;
}

4.信号量例程三

这个示例模拟了一个生产者-消费者问题,其中多个生产者线程和消费者线程共享一个有界缓冲区,信号量用于控制对缓冲区的并发访问。

在此示例中,有三个生产者线程和三个消费者线程,它们共享一个有界缓冲区。Semaphore类用于控制缓冲区的空闲和满状态。生产者线程生成随机项目并将它们放入缓冲区,然后通知消费者线程。消费者线程从缓冲区中取出项目并通知生产者线程。信号量确保缓冲区在多线程环境中得到正确的访问和同步。

这个示例有助于理解信号量在多线程环境中的应用,尤其是在生产者-消费者问题中的作用。通过信号量,可以控制多个线程之间的并发访问,以避免数据竞态和确保正确的协调。

在这里插入图片描述

运行
在这里插入图片描述

代码

#include <condition_variable>
#include <iostream>
#include <mutex>
#include <queue>
#include <thread>
#include <vector>

const int BUFFER_SIZE = 5;

class Semaphore {
  public:
    Semaphore(int count = 0) : count_(count) {}

    void notify() {
        std::unique_lock<std::mutex> lock(mutex_);
        count_++;
        cv_.notify_one();
    }

    void wait() {
        std::unique_lock<std::mutex> lock(mutex_);
        while (count_ == 0) {
            cv_.wait(lock);
        }
        count_--;
    }

  private:
    std::mutex mutex_;
    std::condition_variable cv_;
    int count_;
};

Semaphore empty(BUFFER_SIZE); // 空缓冲区的信号量
Semaphore full(0);            // 满缓冲区的信号量
std::mutex bufferMutex;       // 缓冲区互斥量
std::queue<int> buffer;       // 共享缓冲区

void producer(int id) {
    for (int i = 0; i < 10; ++i) {
        int item = rand() % 100; // 随机生成一个项目
        empty.wait();            // 等待空缓冲区
        bufferMutex.lock();      // 锁定缓冲区
        buffer.push(item);       // 将项目放入缓冲区
        std::cout << "Producer " << id << " produced: " << item << std::endl;
        bufferMutex.unlock(); // 解锁缓冲区
        full.notify();        // 通知缓冲区已满
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
    }
}

void consumer(int id) {
    for (int i = 0; i < 10; ++i) {
        full.wait();        // 等待满缓冲区
        bufferMutex.lock(); // 锁定缓冲区
        int item = buffer.front();
        buffer.pop();
        std::cout << "Consumer " << id << " consumed: " << item << std::endl;
        bufferMutex.unlock(); // 解锁缓冲区
        empty.notify();       // 通知缓冲区已空
        std::this_thread::sleep_for(std::chrono::milliseconds(250));
    }
}

int main() {
    std::vector<std::thread> producers;
    std::vector<std::thread> consumers;

    for (int i = 0; i < 3; ++i) {
        producers.emplace_back(producer, i);
        consumers.emplace_back(consumer, i);
    }

    for (auto &producerThread : producers) {
        producerThread.join();
    }

    for (auto &consumerThread : consumers) {
        consumerThread.join();
    }

    return 0;
}

5.互斥量

在这里插入图片描述

6.PV操作概念

C++中的PV操作通常是指与线程同步和互斥相关的操作,用于实现信号量机制。PV操作通常是Semaphore(信号量)的操作,用于控制多个线程对共享资源的访问。PV操作包括两个主要操作:

  1. P操作(等待操作):也称为down操作,用于获取信号量,并在信号量的值减一之前阻塞线程(如果信号量的值已经为0,则线程将被阻塞)。P操作通常用于锁定临界区,以防止多个线程同时访问共享资源。

    在C++中,可以使用std::mutexstd::unique_lock来实现P操作,也可以使用std::condition_variable来等待信号量的值达到某个条件。

    std::mutex mtx;
    std::unique_lock<std::mutex> lock(mtx);
    
    // 执行P操作,等待互斥锁
    lock.lock();
    // 访问共享资源
    // ...
    lock.unlock();
    
  2. V操作(释放操作):也称为up操作,用于释放信号量,并在信号量的值加一后唤醒一个或多个等待线程。V操作通常用于解锁临界区,以允许其他线程访问共享资源。

    在C++中,可以使用std::mutexstd::unique_lockstd::condition_variable来实现V操作。

    std::mutex mtx;
    std::unique_lock<std::mutex> lock(mtx);
    
    // 执行V操作,释放互斥锁
    lock.unlock();
    // ...
    

请注意,C++标准库还提供了一些高级的同步原语,如std::mutexstd::condition_variablestd::atomic,可以用于更灵活和安全地进行线程同步操作。此外,C++11之后引入的标准库还提供了std::thread来创建和管理线程,以及std::atomic用于原子操作,这些功能有助于更容易地编写多线程应用程序。

7.PV操作详解——抄自:https://mp.weixin.qq.com/s/vvjhbzsWQNRkU7-b_dURlQ

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1062013.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【牛客网-面试必刷TOP 101】01链表

BM1 反转链表 解题思路 第一种方法&#xff1a;借助栈 1. 栈的特点是先进后出&#xff0c;用stack来存储链表&#xff0c;之后新建一个头节点&#xff0c;按出栈顺序拼接形成新的链表。 2. 注意&#xff0c;最后一个节点的next要赋值null 3. 空间复杂度O(N), 时间复杂度O(N)J…

竞赛选题 深度学习 opencv python 公式识别(图像识别 机器视觉)

文章目录 0 前言1 课题说明2 效果展示3 具体实现4 关键代码实现5 算法综合效果6 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 基于深度学习的数学公式识别算法实现 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c;学…

uCOSIII实时操作系统 二 同步与通信

目录 同步概念&#xff1a; 互斥概念&#xff1a; 临界区概念&#xff1a; 任务时间概念&#xff1a; 信号量概念&#xff1a; 互斥信号量概念&#xff1a; 事件标志组概念&#xff1a; 消息邮箱和消息梯队概念&#xff1a; 内存管理概念&#xff1a; 如何从裸机开发…

Linux网络编程1-简单的CS通信程序

Linux网络编程1-简单的CS通信程序 1.Socket相关API说明1.1字节序转换函数&#xff1a;用于ip和port转换1.2sockaddr结构1.3socket函数 以及两个队列1.4bind listen connect accept1.5收发数据 2.服务器和客户端程序代码流程3.服务器端4.客户端5.测试accept不是建立连接而是从已…

1803_ChibiOS网络书籍阅读_嵌入式RTOS介绍

全部学习汇总&#xff1a; GreyZhang/g_ChibiOS: I found a new RTOS called ChibiOS and it seems interesting! (github.com) 1. RTOS指的是实时性操作系统&#xff0c;但是并不是只有嵌入式领域使用RTOS。然而&#xff0c;嵌入式是RTOS的主要使用领域。 2. 一般的RTOS有一组…

国庆中秋宅家自省:偷偷尝鲜

Python3中类的高级语法及实战 Python3(基础|高级)语法实战(|多线程|多进程|线程池|进程池技术)|多线程安全问题解决方案 Python3数据科学包系列(一):数据分析实战 Python3数据科学包系列(二):数据分析实战 Python3数据科学包系列(三):数据分析实战 国庆中秋宅家自省: Pytho…

【visual studio 小技巧】项目属性->生成->事件

需求 我们有时会用到一些dll&#xff0c;需要把这些dll和我们生成的exe放到一起&#xff0c;一般我们是手动自己copy&#xff0c; 这样发布的时候&#xff0c;有时会忘记拷贝这个dll&#xff0c;导致程序运行出错。学会这个小技巧&#xff0c;就能实现自动copy&#xff0c;非…

Ubuntu1804 安装后无法使用root登录解决方法

1. 给root用户设置密码 sudo passwd root2. 确认是否安装ssh服务 (在安装Ubuntu 的时候可以勾选安装ssh 远程服务),没有安装的话执行以下命令(Ubuntu可以连接互联网) sudo apt-get instll openssh-server3. 设置允许root 用户进行远程连接 sudo vim /etc/ssh/sshd_config 在…

10.3 调试事件转存进程内存

我们继续延申调试事件的话题&#xff0c;实现进程转存功能&#xff0c;进程转储功能是指通过调试API使获得了目标进程控制权的进程&#xff0c;将目标进程的内存中的数据完整地转存到本地磁盘上&#xff0c;对于加壳软件&#xff0c;通常会通过加密、压缩等手段来保护其代码和数…

【Ubuntu】基于C++实现人脸识别

人脸识别考勤机 文章目录 人脸识别考勤机概述第一章 搭建Ubuntu环境1.1 什么是物联网1.2 物联网应该怎么学1.3 Linux开发环境搭建1.4 Linux基本使用1.5 Ubuntu网络配置 第二章 “hello,world!”程序2.1 什么是程序2.2 “hello,world!”程序2.3 C语法扩展2.4 常见错误调试 第三章…

Numpy科学计算基础库--numpy基础知识

对数组执行数学运算和逻辑运算时&#xff0c;Numpy 是非常有用的。在用 Python 对 n 维数组和矩阵进行运算时&#xff0c;Numpy 库提供了大量有用特征。Numpy 库数组有两种形式&#xff1a;向量和矩阵。严格地讲&#xff0c;向量是一维数组&#xff0c;矩阵是多维数组。在某些情…

Redis-数据过期策略

数据过期策略 惰性删除策略优点&#xff1a;对cpu比较友好&#xff0c;在用到该key的时候才去进行判断&#xff0c;对于很多用不到key不用浪费时间去检查是否过期缺点&#xff1a;对内存不友好&#xff0c;如果一个key过期了&#xff0c;但是我们又一直没有用到该key&#xff0…

基于YOLOv8的安全帽检测系统(4):EMA基于跨空间学习的高效多尺度注意力、效果优于ECA、CBAM、CA,助力行为检测 | ICASSP2023

目录 1.Yolov8介绍 2.安全帽数据集介绍 3.EMA介绍 4.训练结果分析 5.系列篇 1.Yolov8介绍 Ultralytics YOLOv8是Ultralytics公司开发的YOLO目标检测和图像分割模型的最新版本。YOLOv8是一种尖端的、最先进的&#xff08;SOTA&#xff09;模型&#xff0c;它建立在先前YOLO…

Win11 安装 Vim

安装包&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1Ru7HhTSotz9mteHug-Yhpw?pwd6666 提取码&#xff1a;6666 双击安装包&#xff0c;一直下一步。 配置环境变量&#xff1a; 先配置系统变量中的path&#xff1a; 接着配置用户变量&#xff1a; 在 cmd 中输入…

MySQL 事务隔离级别与锁机制详解

目录 一、前言二、事务及其ACID属性三、并发事务处理带来的问题四、事务隔离级别4.1、隔离级别分类4.2、查看当前数据库的事务隔离级别:4.3、临时修改数据库隔离级别&#xff08;重启MySQL后恢复到配置中的级别&#xff09; 五、表数据准备六、MySQL常见锁介绍5.1、锁分类5.2、…

【网络安全 --- XSS漏洞利用实战】你知道如何利用XSS漏洞进行cookie获取,钓鱼以及键盘监听吗?--- XSS实战篇

一&#xff0c;XSS 实战 以pikachu靶场为例 1-1 盗取cookie 过程&#xff1a;想要盗取别人的cookie信息的话有一个前提条件&#xff0c;就是你应该在别人触发你的xss攻击时&#xff0c;你的代码应该将收集的cookie信息发送给你的平台来接收&#xff0c;这样才获取到了数据 …

图的广度遍历-邻接矩阵实现

description 本题要求实现邻接矩阵存储图的广度优先遍历。 函数接口定义&#xff1a; void BFS(MGraph G,Vertex i); 其中MGraph是邻接矩阵存储的图&#xff0c;定义如下&#xff1a; #define MaxVertexNum 10 /定义最大顶点数/ typedef int Vertex;/* 用顶点下标表示顶点,…

1799_GNU pdf阅读器evince_windows系统下编译尝试

全部学习汇总&#xff1a; GreyZhang/g_GNU: After some years I found that I do need some free air, so dive into GNU again! (github.com) 从网上下载下来了evince的代码&#xff0c;尝试做一个windows下的编译。 这应该是autotools的构建系统&#xff0c;先尝试运行confi…

java做个qq机器人

前置的条件 机器人是基于mirai框架实现的。根据官方的文档&#xff0c;建议使用openjdk11。 我这里使用的编辑工具是idea2023 在idea中新建一个maven项目&#xff0c;虽然可以使用gradle进行构建&#xff0c;不过我这里由于网络问题没有跑通。 pom.xml <dependency>&l…

提示msvcp140.dll丢失的5个解决方法,msvcp140.dll丢失问题全面分析

在我们的日常生活和工作中&#xff0c;电脑已经成为不可或缺的工具。然而&#xff0c;在使用电脑的过程中&#xff0c;我们经常会遇到各种问题&#xff0c;其中就包括提示 msvcp140.dll 丢失的问题。msvcp140.dll 是 Visual C Redistributable for Visual Studio 2015 的运行时…