В моем приложении я получаю сообщения от LCM (Lightweight Communications and Marshalling), которые содержат данные для нескольких потребителей в приложении. Я представлял, как это работает с обработчиком LCM как синглтоном, так что есть один экземпляр, который может использовать каждый класс. Например, каждый потребительский класс будет иметь:
QObject::connect(LCMHandler::getInstance(), SIGNAL(messageReceived()),
this, SLOT(processMessage()));
куда lcmhandler.h
является:
class LCMHandler : public QObject
{
Q_OBJECT
public:
static LCMHandler* getInstance();
LCMHandler();
~LCMHandler() {}
void handleMessage(const lcm::ReceiveBuffer* rbuf,
const std::string &chan,
const example::example_t *msg);
signals:
void messageReceived();
private:
static LCMReceiver* _instance;
};
А также lcmhandler.cpp
является:
LCMHandler* LCMHandler::_instance = 0;
LCMHandler::LCMHandler()
{
lcm::LCM lcm;
if(lcm.good())
{
lcm.subscribe("MyChannel", &LCMHandler::handleMessage, this);
while(0 == lcm.handle());
} else {
std::cerr << "LCM Error" << std::endl;
}
}
LCMHandler* LCMHandler::getInstance() {
if (!_instance) {
_instance = new LCMHandler();
}
return _instance;
}
void LCMHandler::handleMessage(const lcm::ReceiveBuffer *rbuf,
const std::string &chan,
const hlelcm::transponder_t *msg)
{
std::cout << "Received message on channel " << chan.c_str() << std::endl;
emit messageReceived();
}
Приложение успешно печатает «Полученное сообщение на канале …» повторно; тем не менее, ничего не выполняется, в том числе код в классе потребителя processMessage()
, предположительно потому, что приложение застревает в цикле handleMessage(...)
и никогда не выполняет процедуру сигнал / слот (или обновляет компоненты пользовательского интерфейса). Итак, если реализация processMessage()
является:
void Consumer::processMessage() {
std::cout << "Message received" << std::endl;
}
Это никогда не выполняется, пока handleMessage(...)
петли бесконечно. Точно так же интерфейс Qt никогда не загружается, потому что handleMessage занят циклом.
Как лучше всего обрабатывать входящие сообщения? Должен ли я воздерживаться от использования синглтона для LCMHandler
? Что мне нужно изменить, чтобы эта реализация работала?
Переместите содержимое вашего конструктора LCM в другую функцию:
LCMHandler::beginCommunication()
{
lcm::LCM lcm;
if(lcm.good())
{
//QObject base class call.
moveToThread( &_myLocalQThread );
_myLocalThread.start();
lcm.subscribe("MyChannel", &LCMHandler::handleMessage, this);
_isActive = true;
// This is blocking, we don't want it to interfere with
// the QApplication loop
while(0 == lcm.handle());
}
else
{
std::cerr << "LCM Error" << std::endl;
}
_isActive = false;
}
Затем что-то вроде этого, чтобы ваш цикл LCM происходил в другом потоке.
auto lcmHandler = LCMHandler::getInstance();
// I like to be explicit about the Qt::QueuedConnection. Default behavior should be thread safe, though.
connect( lcmHandler, &LCMHandler::messageReceived,
this, &Consumer::processMessage, Qt::QueuedConnection );
// Add a std::atomic< bool > _isActive to LCMHandler
if( not lcmHandler.isActive() )
{
lcmHandler.beginCommunication();
}
И затем убедитесь, что правильно закрыли свой QThread в деструкторе.
LCMHandler::~LCMHandler()
{
_myLocalQThread.quit();
_myLocalQThread.wait();
}
Других решений пока нет …