这是在C ++中实现有界缓冲区的正确方法 [英] Is this a correct way to implement a bounded buffer in C++

查看:205
本文介绍了这是在C ++中实现有界缓冲区的正确方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am working on a program that deals with multiple threads accessing, depositing in, and withdrawing from a bounded buffer container. I have noticed some major problems with the threads and suspect that my buffer is partially or fundamentally incorrect somewhere.

为了确定我知道我在做什么,我希望我的缓冲区代码看起来。该类使用了一个我在其他地方实现的信号量,我将假设现在工作(如果没有,我很快就会找到它!)我添加了意见,试图解释我的推理。

To be sure I know what I am doing with this, I would appreciate having my buffer code looked over. The class uses a Semaphore that I implemented elsewhere, which I will assume works for now (if not, I'll figure that out soon enough!) I have added comments that attempt to explain my reasoning.

首先是.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; 
}

我认为问题可能来自于我选择一个向量作为底层容器(或者,而是不正确的使用它),或者可能需要更多的阻止机制的安全性(互斥锁,等等?)从东西的外观,任何人都可以提供一些反馈?

I think that issues could arise from my choice of a vector as the underlying container (or, rather, an incorrect use of it), or perhaps the need for more blocking mechanisms for safety (mutex locks, etc.?) From the looks of things, can anyone offer some feedback?

推荐答案

这是一个非常常见的问题(关于如何做一个正确的多线程队列)。我见过的最好的答案是这个堆栈溢出问题本网站

This is an extremely common question (about how to do a proper multithreaded queue). The best answers I have seen before is this stack overflow question and this web site. Those answers are for unbounded queues, so I will expand and show an answer for a bounded queue here.

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

You need to protect your Deposit and Retrieve functions with mutexes and use condition variables to do the wake ups.

#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保护。

Your GetNumItems(), GetBuffer() and SetSize() functions also need to be protected with unique_locks.

这篇关于这是在C ++中实现有界缓冲区的正确方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆