这是在 C++ 中实现有界缓冲区的正确方法吗?

2023-11-23

我正在开发一个程序,该程序处理多个线程访问、存入和从有界缓冲区容器中取出的问题。我注意到线程的一些主要问题,并怀疑我的缓冲区在某处部分或根本不正确。

为了确保我知道我在做什么,我希望检查一下我的缓冲区代码。该类使用了我在其他地方实现的信号量,我假设它现在可以工作(如果没有,我很快就会弄清楚!)我添加了试图解释我的推理的注释。

首先,.h 文件:

#ifndef BOUNDED_BUFFER_H
#define BOUNDED_BUFFER_H

#include "Semaphore.H"
#include <string> 
#include <vector>  

using namespace std; 

class Item{ //supposed to eventually be more extensible...seems silly with just a string for now

  public:
    Item(string _content){content = _content;} 
    string GetContent() {return content;}     

  private:  
};   

    class BoundedBuffer{

      public:
        BoundedBuffer(); 

        void Deposit(Item* _item); 
        Item* Retrieve();        
        int GetNumItems() {return count;} 
        vector<Item*> GetBuffer() {return buffer;} 
        void SetSize(int _size){
          capacity = _size;
          buffer.reserve(_size);  //or do I need to call "resize" 
        }  

      private:
        int capacity; 
        vector<Item*> buffer; //I originally wanted to use an array but had trouble with  
                              //initilization/sizing, etc. 
        int nextin; 
            int nextout; 
            int count; 

            Semaphore notfull;   //wait on this one before depositing an item
            Semaphore notempty;  //wait on this one before retrieving an item
        };

    #endif

接下来是.cpp:

#include "BoundedBuffer.H"
#include <iostream>

using namespace std; 

BoundedBuffer::BoundedBuffer(){

  notfull.SetValue(0); 
  notempty.SetValue(0); 
  nextin = 0; 
  nextout = 0; 
  count = 0; 
}

void BoundedBuffer::Deposit(Item* _item){
  if(count == capacity){ 
    notfull.P(); //Cannot deposit into full buffer; wait
  }

  buffer[nextin] = _item; 
  nextin = (nextin + 1) % capacity;  //wrap-around
  count += 1;
  notempty.V();  //Signal that retrieval is safe 
}

Item* BoundedBuffer::Retrieve(){
  if(count == 0){
    notempty.P(); //cannot take from empty buffer; wait 
  }

  Item* x = buffer[nextout]; 
  nextout = (nextout + 1) % capacity;
  buffer.pop_back();  //or a different erase methodology? 
  count -= 1; 
  notfull.V(); //Signal that deposit is safe 
  return x; 
}

我认为问题可能是由于我选择一个向量作为底层容器(或者更确切地说,错误使用它),或者可能需要更多的安全阻塞机制(互斥锁等?)事情,有人可以提供一些反馈吗?


这是一个非常常见的问题(关于如何正确执行多线程队列)。我以前见过的最好的答案是这个堆栈溢出问题 and 这个网站。这些答案适用于无界队列,因此我将在此处扩展并显示有界队列的答案。

您需要使用互斥体保护您的存款和检索功能,并使用条件变量来进行唤醒。

#include <mutex>
#include <condition_variable>

std::mutex the_mutex;
std::condition_variable the_notfull_cvar;
std::condition_variable the_notempty_cvar;

...

void BoundedBuffer::Deposit(Item* _item){
  std::unique_lock<std::mutex> lock(the_mutex);
  while ( /* buffer is full */ ){
    /* simultaneously wait and release the mutex */
    the_notfull_cvar.wait(lock);
    /* the mutex is reaquired at this point */
  }

  /* buffer has space and we own the mutex: insert the item */
  ...
  /* tell anyone waiting on an empty buffer that they can wake up. */
  the_notempty_cvar.notify_all();
}

Item* BoundedBuffer::Retrieve(){
  std::unique_lock<std::mutex> lock(the_mutex);
  while ( /* buffer is empty */ ){
    /* simultaneously wait and release the mutex */
    the_notempty_cvar.wait(lock);
    /* the mutex is reaquired at this point */
  }

  /* buffer has something in it and we own the mutex: get the item */
  ...
  /* tell anyone waiting on a full buffer that they can wake up. */
  the_notfull_cvar.notify_all();

  return x;
}

您的 GetNumItems()、GetBuffer() 和 SetSize() 函数也需要使用 unique_locks 进行保护。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

这是在 C++ 中实现有界缓冲区的正确方法吗? 的相关文章

  • 从结构调用 C++ 成员函数指针

    我找到了有关调用 C 成员函数指针和调用结构中的指针的信息 但我需要调用结构内部存在的成员函数指针 但我无法获得正确的语法 我在类 MyClass 的方法中有以下代码片段 void MyClass run struct int MyClas
  • Visual Studio 2013 调试器显示 std::string 的奇怪值

    我有一个大型的 cmake 生成的解决方案 其中包含许多项目 由于某种原因 我无法查看字符串的内容 因为根据调试器 Bx Buf含有一些垃圾 text c str 正确返回 Hello 该问题不仅仅发生在本地字符串上 返回的函数std st
  • 我担心我添加了太多接口

    我正在构建我的领域模型并继续重构它 正如我所做的那样 我发现我喜欢接口 因为它允许我根据接口为具体类型创建可重用的方法 控制器 视图 但是 我发现每次向域实体之一添加新属性时 我都会创建一个接口 例如 我有一个会员状态从抽象继承的对象Ent
  • 维护 VS Test Project 中单元测试方法之间的上下文

    我想按顺序运行以下单元测试 使用随机数字的名称 密码等创建新客户 检索刚刚创建的客户并断言其属性包含相同的随机数 对同一用户调用 ForgotPassword 函数 并使用相同的随机数作为用户名 清楚地看到 我需要生成一次随机数 并在 3
  • 加载 QPixmap 数据的更好方法

    更好的方法来做到这一点 没有QImage QImage image width height QImage Format RGB888 memcpy image bits m frameRGB gt data 0 height width
  • 公交车公共交通算法

    我正在开发一个可以查找公交路线的离线 C 应用程序 我可以提取时间表 巴士 路线数据 我正在寻找适用于基本数据的最简单的解决方案 可以使用什么算法来查找从巴士站 A 到巴士站 B 的路线 是否有适用于 C Java 的开源解决方案 数据库的
  • 自己绘制的WPF自定义滑块

    这是我关于堆栈溢出的第一个问题 所以不要踢它 我在尝试创建 Mac 风格的滑块控件时遇到问题 我已经发现这个解决方案 http www codeproject com KB miscctrl MAC Slider aspx我已经在我的解决方
  • 从图像创建半透明光标

    是否可以从图像创建光标并使其半透明 我目前正在拍摄自定义图像并覆盖鼠标光标图像 如果我可以将其设为半透明 那就太好了 但不是必需的 销售人员喜欢闪亮的 目前正在做这样的事情 Image cursorImage customImage Get
  • 如何在 C 中链接目标文件?失败并显示“架构 x86_64 的未定义符号”

    因此 我尝试在我的文件 file2 c 中使用另一个 C file1 c 文件中定义的函数 为了做到这一点 我包含了 file1 file1 h 的标头 但是 每当我尝试使用 gcc 编译文件时 我都会收到以下错误 Undefined sy
  • 当我尝试传递临时地址作为参数时,它是一个 UB 吗?

    对于以下 C 代码 include
  • 如何从 Powerpoint 2010 导出电影?

    如何使用 MS Office PIA 主互操作程序集 或其他方式以编程方式将嵌入视频从 powerpoint 2010 导出到外部文件 在演示文稿中嵌入视频是 Powerpoint 2010 中的一项新功能 我找不到解决方案 PPTX 文件
  • 为什么连续抛出 2 个异常不会生成无法访问的代码警告?

    为什么以下代码行不会创建编译器警告 void Main throw new Exception throw new Exception 据我所知 编译器应该通知您无法到达第二个抛出异常 这显然是一个编译器错误 它是在 C 3 0 中引入的
  • MINIX内部碎片2

    我正在用 C 语言编写一些软件 它递归地列出给定目录中的所有文件 现在我需要计算出内部碎片 我花了很长时间研究这个问题 发现 ext2 上的内部碎片只发生在最后一个块中 我知道理论上你应该能够从索引节点号获得第一个和最后一个块地址 但我不知
  • MPI - 发送和接收列

    我需要从一个进程发送矩阵列并从另一个进程接收它 我尝试运行以下程序 但得到了一个奇怪的结果 至少我这么认为 仅复制矩阵的第一个元素 某些矩阵元素会发生意外变化 include
  • Clang 5.0 上的 vsprintf 和 vsnprintf [-Wformat-nonliteral] 警告

    我有这段代码 static void err doit int errnoflag int level const char fmt va list ap int errno save unsigned long n char buf MA
  • 在 Visual Studio 2012 Express 中设置 C++ 调试环境

    我需要调试的应用程序需要设置环境变量 这在 Visual Studio 2012 中似乎非常复杂 我想做类似的事情 set path c foo c bar c windows c program files application set
  • Windows Phone 的 JSON 反序列化

    我正在尝试反序列化以下 JSON 但我真的不知道如何使用 JSON net 来完成这项工作 我正在使用 C 和 JSON Net 库 我的 JSON 如下 found 3 bounds 43 54919 172 62148 43 54487
  • 在多线程环境中捕获信号

    我有一个大型程序 需要尽可能具有弹性 并且有大量线程 我需要捕获所有信号SIGBUS SIGSEGV 并在必要时重新初始化有问题的线程 或者禁用该线程以继续减少功能 我的第一个想法是做一个setjump 然后设置信号处理程序 可以记录问题
  • 尝试后终于没有被调用

    由于某种原因 在我的控制台应用程序中 我无法运行我的finally 块 我编写这段代码是为了测试finally块是如何工作的 所以它非常简单 static void Main int i 0 try int j 1 i Generate a
  • NHibernate:无状态会话错误消息无法获取代理

    我正在使用 nHibernate 无状态会话来获取对象 更新一个属性并将对象保存回数据库 我不断收到错误消息 无状态会话无法获取代理 我在其他地方有类似的代码 所以我不明白为什么这不起作用 有谁知道问题可能是什么 我正在尝试更新Screen

随机推荐

  • 为什么 mac chrome 上的选择框不响应点击事件? [复制]

    这个问题在这里已经有答案了 可能的重复 JQuery 函数不适用于 Mac 上的 Chrome 但适用于 Win 7 上的 Chrome 和所有其他浏览器 我有一个选择选项列表 div class social option div
  • 带标题的 window.open

    我可以控制发送的 HTTP 标头吗window open 跨浏览器 如果没有 我可以以某种方式window open然后在弹出窗口中使用自定义标头发出我的请求的页面 我需要一些狡猾的技巧 我可以控制window open 跨浏览器 发送的H
  • 在 Android Marshmallow 中请求多个蓝牙权限

    我正在开发一个具有连接功能的应用程序 该应用程序连接到使用 SDK 23 进行编译的蓝牙设备 我在请求蓝牙的多个权限时遇到问题 这是我到目前为止所做的 Override public void onStart super onStart i
  • 这里如何去掉trace0呢?

    信息 trace0 始终显示在蓝线的悬停文本框旁边 如何删除它 为什么不在橙线上 Trace0到底是什么意思 library plotly fig lt plot ly fig lt fig gt add trace type scatte
  • C#更改框架错误

    我正在运行 Visual Studio 2010 我只是将项目的框架从 4 0 更改为 3 5 我删除了它要求我删除的引用 Microsoft Framework 然后尝试编译 我现在收到错误 错误 1 无法加载文件或 装配 系统 绘图 版
  • 海湾合作委员会优化?漏洞?及其对项目的实际意义

    我的问题分为三个部分 问题1考虑下面的代码 include
  • 从路径字符串中获取类似树的结构

    我已经被困了两天了 因为我对指针和递归不太坚定 我有一系列类似路径的结构 可以说 s string a b c a b g a d 具有这样的数据结构 type Node struct Name string json name Child
  • 如何在RecyclerView中选择和取消选择项目?如何仅在回收者视图中突出显示所选项目?

    Override public void onBindViewHolder final mainscreenspecializationadap MyViewHolder holder final int positionz this po
  • 如何访问ThreadPoolExecutor内部正在运行的线程?

    我有一个正在运行的线程队列 并且希望在执行时公开其一些数据 以监视进程 ThreadPoolExecutor提供对其队列的访问 我可以迭代这些对象来调用我的重写toString 方法 但这些只是等待执行的线程 有没有办法访问当前正在运行的线
  • CSS Translate:translate() 属性最终的用途是什么?

    在 CSS3 中 动画是在各种供应商前缀下引入的 并带有过渡属性 现在 至少在纯 CSS 中 有两种方法可以使元素改变位置 将元素的位置设置为绝对位置并进行调整left right top and bottom Using vendor t
  • 当主线程繁忙时如何让Qt工作?

    我的程序的主线程 函数 main 在那里 是为非 GUI 任务保留的 它调用了许多冗长的计算函数 所有实现的 GUI 都在单独的线程中完成其工作 我现在将使用 Qt 实现另一个 GUI Qt 文档说所有与 GUI 相关的任务都应该在主线程中
  • 如何在本地下载pip依赖项? [复制]

    这个问题在这里已经有答案了 我正在运行我的 python 应用程序requirements txt包含各种依赖项的文件 我正在 Pivotal Cloud Foundry 环境中部署此应用程序 然而 我在其中部署的环境是气隙的 因此我似乎无
  • Django URLS,使用 ?在网址中

    我正在尝试进行一些 Django URL 匹配 我想要一些我有的网址http mysite com base sort type1 http mysite com base sort type2 etc 我不知道如何 URL 匹配这些表达式
  • 配置来自 Nifi 的 HTTP POST 请求

    我正在尝试从 REST 客户端访问 WCF 服务 我正在从 REST 客户端向 WCF 服务发送 POST 请求 详细如下 供大家参考 The 服务合同定义如下 ServiceContract public interface IBZTso
  • UWP 中的自定义内容对话框包含 3 个以上按钮

    我想显示一个内容对话框 其中包含比传统的主要和次要结果更多的内容 由于我无法重写 ContentDialogResult 枚举并向该属性添加选项 因此我似乎唯一的选择可能是创建自己的自定义控件 其工作方式与 ContentDialog 类似
  • AppDelegate for Cocoa 应用程序在 Xcode 6 中使用 Storyboards

    我有一个现有的 OS X 应用程序 在转换为 Storyboards 作为主界面后 我的应用程序委托不再被使用 之前 MainMenu xib 有一个 App Delegate 对象 我可以将其类设置为我的应用程序委托 然而 故事板不包含这
  • Chrome Service Worker iOS 支持

    随着 Apple 几个月前宣布 Service Worker 支持 iOS 11 3 我最近开始尝试让 Service Worker 在 iOS 上工作 在 Safari 上 它按预期工作 访问网站后 它可以离线工作 然而 当我尝试在 Ch
  • “6k 浏览次数”是什么意思以及如何在 PHP 中格式化该数字

    6k 浏览次数 是什么意思以及如何在 PHP 中格式化这个数字 k是缩写基洛前缀并表示千 所以6k就是六千 您可以使用以下除法函数来格式化数字 function format number prefixes kMGTPEZY if numb
  • SQL Server MERGE + 连接其他表

    我在数据库项目中使用 MERGE 语句从静态值集中填充参考数据 如下所示 MERGE INTO dbo User AS TARGET USING VALUES email protected My Name AS SOURCE UserNa
  • 这是在 C++ 中实现有界缓冲区的正确方法吗?

    Closed 这个问题是无关 目前不接受答案 我正在开发一个程序 该程序处理多个线程访问 存入和从有界缓冲区容器中取出的问题 我注意到线程的一些主要问题 并怀疑我的缓冲区在某处部分或根本不正确 为了确保我知道我在做什么 我希望检查一下我的缓