2012-04-13 15 views
11

Ich habe eine Anwendung, die geschrieben wird, um boost::asio ausschließlich als Quelle von Eingabedaten zu verwenden, da die meisten unserer Objekte Netzwerkkommunikation basieren. Aufgrund bestimmter Anforderungen benötigen wir jetzt die Möglichkeit, gemeinsam genutzten Speicher als Eingabemethode zu verwenden. Ich habe bereits die Shared Memory-Komponente geschrieben und es funktioniert relativ gut.Boost :: Asio, Shared Memory und Interprozesskommunikation

Das Problem besteht darin, wie Benachrichtigungen aus dem Shared-Memory-Prozess an die konsumierende Anwendung, dass Daten zum Lesen verfügbar sind behandelt werden - wir müssen die Daten im vorhandenen Eingabe-Thread behandeln (mit boost::asio), und wir müssen auch blockieren Sie diesen Eingabe-Thread nicht, der auf Daten wartet.

Ich habe dies implementiert, indem ich einen Zwischen-Thread eingeführt habe, der auf Ereignisse wartet, die vom Shared-Memory-Provider-Prozess signalisiert werden, und einen Abschluss-Handler an den Eingabe-Thread sendet, um das Einlesen der Daten zu verarbeiten.

Dies funktioniert jetzt auch, aber die Einführung der Zwischen-Thread bedeutet, dass in einer erheblichen Anzahl von Fällen haben wir einen zusätzlichen Kontext wechseln, bevor wir die Daten lesen können, die sich negativ auf die Latenz und den Overhead der zusätzlicher Faden ist auch relativ teuer.

Hier ist ein sehr einfaches Beispiel dafür, was die Anwendung tun wird:

#include <iostream> 
using namespace std; 

#include <boost/asio.hpp> 
#include <boost/thread.hpp> 
#include <boost/scoped_ptr.hpp> 
#include <boost/bind.hpp> 

class simple_thread 
{ 
public: 
    simple_thread(const std::string& name) 
     : name_(name) 
    {} 

    void start() 
    { 
     thread_.reset(new boost::thread(
     boost::bind(&simple_thread::run, this))); 
    } 

private: 
    virtual void do_run() = 0; 

    void run() 
    { 
     cout << "Started " << name_ << " thread as: " << thread_->get_id() << "\n"; 
     do_run(); 
    } 


protected: 
    boost::scoped_ptr<boost::thread> thread_; 
    std::string name_; 
}; 

class input_thread 
    : public simple_thread 
{ 
public: 
    input_thread() : simple_thread("Input") 
    {} 

    boost::asio::io_service& svc() 
    { 
     return svc_; 
    } 

    void do_run() 
    { 
     boost::system::error_code e; 
     boost::asio::io_service::work w(svc_); 
     svc_.run(e); 
    } 

private: 
    boost::asio::io_service svc_; 
}; 

struct dot 
{ 
    void operator()() 
    { 
     cout << '.'; 
    } 
}; 

class interrupt_thread 
    : public simple_thread 
{ 
public: 
    interrupt_thread(input_thread& input) 
     : simple_thread("Interrupt") 
     , input_(input) 
    {} 

    void do_run() 
    { 
     do 
     { 
     boost::this_thread::sleep(boost::posix_time::milliseconds(500)); 
     input_.svc().post(dot()); 
     } 
     while(true); 
    } 

private: 
    input_thread& input_; 
}; 

int main() 
{ 
    input_thread inp; 
    interrupt_thread intr(inp); 

    inp.start(); 
    intr.start(); 

    while(true) 
    { 
     Sleep(1000); 
    } 
} 

Gibt es eine Möglichkeit, die Daten in den direkt input_thread behandelt zu erhalten (ohne sie über die interrupt_thread um post mit der Annahme ist, dass Der Interrupt-Thread wird vollständig von Zeitvorgaben einer externen Anwendung gesteuert (Benachrichtigung, dass Daten über ein Semaphor verfügbar sind). Außerdem wird davon ausgegangen, dass wir sowohl die konsumierenden als auch die bereitstellenden Anwendungen vollständig kontrollieren können und zusätzliche Objekte benötigen das Objekt input_thread (so können wir nicht einfach auf die Semaphor-Objekte dort blockieren und warten) Ziel ist es, den Overhead, die CPU-Auslastung und die Latenz der Daten zu reduzieren, die über den gemeinsam genutzten Speicher, der die Anwendung bereitstellt, eingehen.

+2

Wenn Sie * NIX verwenden, besteht der einfachste Ansatz darin, eine UNIX-Pipe zur Benachrichtigung zu verwenden, sodass ein Ende der Pipe zum 'input_thread' als normaler Socket hinzugefügt wird. Sie verursachen immer noch den Overhead für die Synchronisation usw., speichern aber eine redundante Kopie (zum/vom Socket-Puffer). Sie können Offset und Länge über den Socket senden und den shmem dann direkt indizieren. – Useless

+0

In Windows können Sie windows :: object_handle verwenden, um asynchrone Warte direkt auf Ihrem Synchronisierungsobjekt zu verwenden. –

Antwort

1

Ich denke, Sie Ihre Antwort gefunden haben, seit Sie diese Frage gestellt, ist dies für andere profitieren ...

Versuch und strands Schub überprüfen.

Es gibt Ihnen die Möglichkeit zu wählen, auf welchen Thread Sie arbeiten möchten.

Es wird automatisch in die Warteschlange gestellt, das ist etwas, über das Sie nicht nachdenken müssen.

Es gibt Ihnen sogar einen Abschluss-Handler, wenn Sie wissen müssen, wann die Arbeit erledigt ist.