2016-12-15 29 views
1

在我的應用程序中,我接收來自LCM(輕量級通信和編組)的消息,其中包含應用程序中多個消費者的數據。我設想這個LCM處理程序作爲一個單例使用,以便每個類都可以使用一個實例。例如,每個消費階層將有:通過Qt中的C++中的信號/插槽接收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(...)上循環並從不執行信號/插槽過程(或刷新UI組件)。因此,如果processMessage()實現如下:

void Consumer::processMessage() { 
    std::cout << "Message received" << std::endl; 
} 

它從未執行,而handleMessage(...)無限循環。同樣,Qt UI永遠不會加載,因爲handleMessage忙於循環。

處理傳入消息的最佳方法是什麼?我是否應該避免使用LCMHandler的單身人士?我需要更改哪些內容才能使此實現有效?

+0

看起來像單身人士可能需要住在它自己的線程,如果這是阻止它的構造? while(0 == lcm.handle()); – DaveyLaser

回答

0

移動你的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(); 
}