Produzent/konsument mit boost threads und zirkulären Puffer hängt
Habe ich es herausgefunden. Dumme Fehler meinerseits, war ich eigentlich nicht löschen das element aus der queue, ich war nur zu Lesen das erste element. Ich veränderte den code, und der code unten nicht funktioniert. Vielen Dank an alle für die Hilfe.
Ich versuche zur Umsetzung der producer-consumer-problem mit boost, das ist eigentlich Teil eines größeren Projekts. Ich habe ein Programm eingeführt, nach Beispielen im internet und sogar einige Hilfe habe ich hier gefunden. Aber derzeit mein code hängt nur. Basierend auf ein paar gute Ratschläge, ich habe mich für die boost-ciruclar Puffer zur Speicherung meiner Daten zwischen Erzeuger und Verbraucher. Viel ähnlichen code gibt, und ich war in der Lage zu bündeln, um Ideen aus und schreiben etwas auf meinem eigenen. Aber ich Schaffe es immer noch mit demselben problem wie vorher (was mein Programm gerade hängt). Ich dachte, dass ich nicht den gleichen Fehler machen wie zuvor..
Mein code ist unten angegeben, ich habe aus meinen früheren code, wo ich nur meine eigene einzeln link-Liste.
Puffer-header:
#ifndef PCDBUFFER_H
#define PCDBUFFER_H
#include <pcl/io/pcd_io.h>
#include <boost/thread/mutex.hpp>
#include <boost/thread/condition.hpp>
#include <boost/circular_buffer.hpp>
class pcdBuffer
{
public:
pcdBuffer(int buffSize);
void put(int data);
int get();
bool isFull();
bool isEmpty();
int getSize();
int getCapacity();
private:
boost::mutex bmutex;
boost::condition_variable buffEmpty;
boost::condition_variable buffFull;
boost::circular_buffer<int> buffer;
};
#endif
Buffer source (nur die relevanten Teile):
#include "pcdBuffer.h"
#include <iostream>
//boost::mutex io_mutex;
pcdBuffer::pcdBuffer(int buffSize)
{
buffer.set_capacity(buffSize);
}
void pcdBuffer::put(int data)
{
{
boost::mutex::scoped_lock buffLock(bmutex);
while(buffer.full())
{
std::cout << "Buffer is full" << std::endl;
buffFull.wait(buffLock);
}
buffer.push_back(data);
}
buffEmpty.notify_one();
}
int pcdBuffer::get()
{
int data;
{
boost::mutex::scoped_lock buffLock(bmutex);
while(buffer.empty())
{
std::cout << "Buffer is empty" << std::endl;
buffEmpty.wait(buffLock);
}
data = buffer.front();
buffer.pop_front();
}
buffFull.notify_one();
return data;
}
wichtigsten Treiber für den code:
#include <iostream>
#include <boost/thread/mutex.hpp>
#include <boost/thread/thread.hpp>
#include <unistd.h>
#include "pcdBuffer.h"
pcdBuffer buff(100);
void producer()
{
int i = 10;
while (true)
{
buff.put(i);
i++;
}
}
void consumer()
{
int i;
while(true)
{
i = buff.get();
std::cout << "Data: " << i << std::endl;
}
}
int main(int argc, char** argv)
{
std::cout << "Starting main...." << std::endl;
std::cout << "Buffer Details: " << std::endl;
std::cout << "Capacity: " << buff.getCapacity() << ", isEmpty: " << buff.isEmpty() << ", isFull: " << buff.isFull() << std::endl;
boost::thread cons(consumer);
sleep(5);
boost::thread prod(producer);
prod.join();
cons.join();
return 0;
}
Mein Puffer Kapazität wird richtig initialisiert, um 100. Der Verbraucher-thread wartet, und berichtet, dass die "Puffer ist leer" für die 5 Sekunden, aber danach bekomme ich nur den "Puffer ist voll" aus der put-Methode und "Daten : 10" von der Verbraucher-Funktion abwechselnd auf stdout. Wie Sie sehen können, 10 ist das erste element, das ich in. Es scheint, dass der Puffer immer gefüllt und nicht notifiying die Verbraucher, aber ich habe meine Schlösser, und denke, Sie haben Recht. Jede Hilfe zu diesem wird sehr geschätzt.
Hier noch ein link von Referenzen, von denen ich schrieb diesen code:
http://www.drdobbs.com/article/print?articleId=184401518&siteSectionName=cpp
Thread-sichere Implementierung der zirkulären Puffer
- Schauen Sie mal hier: justsoftwaresolutions.co.uk/threading/...
- , Der Artikel ist wirklich interessant, aber ein weiterer Grund möchte ich vermeiden stl-Warteschlangen ist die Geschwindigkeit. Schließlich, die Daten-Struktur, die ich teilen werden zwischen threads ist die Punktwolke repräsentiert einen frame capture aus einer kinect-ähnlichen Kamera. Ich möchte capture frames bei 30fps und speichern Sie disk. Damit möchte ich minimieren, meinen Aufwand so viel wie möglich. Das ist ein weiterer Grund vermied ich es, STL-Warteschlangen. Ich habe versucht zu entsperren meine locken, bevor die Benachrichtigung der Bedingung Variablen, wie der Artikel vermuten lässt, sondern es hängt noch. Ich habe aktualisiert mein code hier.
- Zuerst seine Arbeit machen, dann machen es schnell. Vermeiden Sie Annahmen darüber, welche Teile des Codes/design wird langsam sein. Vermeiden Sie vorzeitige Optimierung. Konzentrieren Sie Ihre Arbeit auf dem wichtigen Teil, während unter Verwendung von standard-Komponenten, wo möglich. Wenn es sich herausstellt, zu langsam, Maß, das Teil ist langsam und DANN zu optimieren, dass ein Teil.
- Das war manchen guten Rat. Habe ich kopiert und implementiert den code aus dem verlinkten Artikel von stefaanv und es ist viel einfacher zu Folgen und zu verstehen, als meinen hässlichen code. Ich werde versuchen, dies mit dem point-cloud-Daten-und hoffentlich wird es schnell genug sein für das, was ich brauche.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Zunächst, statt zu schreiben Ihre eigene Liste, Sie konnte nur wickeln
std::list
impcdQueue
statt zu schreiben Ihre eigenen. Es ist richtig, dassstd::list
ist nicht thread-safe ist, aber Sie sind die Bereitstellung der notwendigen synchronisation primitiven in Ihrer Klasse sowieso.Der Grund, warum Ihr Programm hängt:
Halten Sie den Verschluss und füllen Sie die Warteschlange, bis Sie voll ist. Ihre notificaiton der Verbraucher über
notify_one
ist nutzlos, weil Ihre Verbraucher wird die Sperre wieder rechts, da der mutex schon vergeben ist (durch die lock-in-Produzenten).Wenn Sie endlich die Sperre freigeben (wenn die Warteschlange voll) wartet auf die
condition_variable
Sie nicht aufwachen Ihre Verbraucher, so dass beide Ihre Verbraucher und Ihre Produzenten sind blockiert und das Programm hängt sich auf.Ändern:
Haben Sie die gleichen Probleme in Ihrem
consume()
Methode. Ändern Sie es zu:Im Allgemeinen, seien Sie vorsichtig und beachten Sie, dass Benachrichtigungen nur einen Effekt haben, wenn jemand wartet. Ansonsten sind Sie "verloren". Beachten Sie außerdem, dass Sie nicht brauchen, zu halten, der den mutex gesperrt beim Aufruf
notify_one
(in der Tat, es kann dazu führen, zusätzliche Kontext-switch-overhead, weil du aufwachst, der andere thread wird dann warten auf ein mutex, die derzeit (noch) gesperrt (durch Sie). Also erstmal, das mutex freizugeben, dann sagen Sie dem anderen thread weiter.Bitte beachten Sie, dass beide threads laufen unendlich, so dass Ihr Haupt-Programm hängen immer noch an der ersten
join()
und nie beendet. Sie könnte auch ein beenden-flag, das Sie checkn in Ihremwhile
-loops zu sagen, Ihre threads zu beenden.Boost bietet eine producer/consumer-Warteschlange-geben Sie nun, in der lockfree Abschnitt, der weitgehend lockfree obwohl es MÖGLICHERWEISE gesperrt, wenn die Warteschlange voll ist.
Finden Sie die Dokumentation hier:
http://www.boost.org/doc/libs/1_54_0/doc/html/lockfree.html
Es ist ein ziemlich Neuzugang, also ich glaube nicht, dass es Teil der vielen standard-Pakete noch. Auf der anderen Seite, das sieht aus wie die meisten Header, die alle je auf einer ziemlich low-level-system-Sachen, die schon im Aufschwung für eine lange Zeit.
Stieß ich auf das gleiche Problem zu hängen. Dank Johannes' Antwort, ich war in der Lage, damit es funktioniert völlig. Allerdings, musste ich
voll.wait_for(lock, boost::chrono::milliseconds(100));
sowohl die Verbraucher und die Produzenten, zu verhindern hängen, wenn mit sehr kurzen kreisförmigen Puffer (3-4 Elemente).
Auch, statt while (true), die ich verwendet, während die (Puffer->leer().
Schließlich, alles funktioniert zuverlässig und schnell.