Tengo una aplicación que está escrita para usar boost::asio
exclusivamente como fuente de datos de entrada ya que la mayoría de nuestros objetos están basados en la comunicación de red. Debido a algunos requisitos específicos, ahora también se requiere la posibilidad de utilizar la memoria compartida como método de entrada. Ya escribí el componente de memoria compartida y funciona relativamente bien.Boost :: asio, memoria compartida y comunicación entre procesos
El problema es cómo manejar las notificaciones del proceso de memoria compartida a la aplicación consumidora que los datos están disponibles para ser leídos; necesitamos manejar los datos en el hilo de entrada existente (usando boost::asio
), y también necesitamos no bloquear ese hilo de entrada en espera de datos.
Implementé esto al introducir un subproceso intermedio que espera sucesos que se señalizarán desde el proceso de proveedor de memoria compartida y luego publica un controlador de finalización en el subproceso de entrada para controlar la lectura en los datos.
Esto está funcionando ahora también, pero la introducción del hilo intermedio significa que en una cantidad significativa de casos tenemos un cambio de contexto adicional antes de poder leer los datos que tienen un impacto negativo en la latencia, y la sobrecarga del hilo adicional también es relativamente costoso.
Aquí está un ejemplo simplista de lo que está haciendo la aplicación:?
#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);
}
}
¿Hay alguna manera de obtener los datos que se manejan en el input_thread
directamente (sin tener que post
en medio de la interrupt_thread
La suposición es que el hilo de interrupción está totalmente controlado por los tiempos de una aplicación externa (notificación de que los datos están disponibles a través de un semáforo). Además, supongamos que tenemos control total de las aplicaciones que consumen y proporcionan, que tenemos objetos adicionales que deben ser manejados por el objeto input_thread
(por lo que no podemos simplemente bloquear y esperar los objetos de semáforo allí). El objetivo es reducir la sobrecarga, la utilización de la CPU y la latencia de los datos que ingresan a través de la aplicación de suministro de memoria compartida.
Si está usando * NIX, el enfoque más fácil es utilizar una tubería UNIX para notificar, por lo que un extremo de la tubería se agrega al 'input_thread' como un socket normal. Aún incurre en la sobrecarga de sincronización, etc., pero guarda una copia redundante (en/desde el búfer del zócalo). Puede enviar desplazamiento y longitud sobre el zócalo, y luego indexar el shmem directamente. – Useless
En Windows, es posible que pueda usar windows :: object_handle para async esperar directamente en su objeto de sincronización. –