0
votes

I'm trying to pass a custom class pointer (With using polymorphism) to another by using signal slot mechanism. Basically I have a base class and multiple derived classes (They are not extended from QObject) and I'm trying to pass the base class to another thread by using signal slot mechanism as described in below example. When I do that I can succesfully transfer the base class pointer to another thread but when I try to downcast it , or call the virtual method I got sigsegv exception . I've searched through lots of articles but wasnt able to find a proper solution, does anyone has experienced such problem before?

This is the part which I've created the worker threads

qRegisterMetaType<SecondMessage>();
for (const auto& receiver : glimpseReceivers) {
    QThread *thread = new QThread();
    receiver->moveToThread(thread);
    QObject::connect(thread, SIGNAL(started()), receiver.get(), SLOT(start()));
    QObject::connect(receiver.get(), SIGNAL(finished()), thread, SLOT (quit()));
    QObject::connect(receiver.get(), SIGNAL (finished()), receiver.get(), SLOT (deleteLater()));
    QObject::connect(thread, SIGNAL(finished()), thread, SLOT (deleteLater()));
    QObject::connect(receiver.get(),&MAGlimpseReceiver::sequenceNumberReceived,this,&MAItchManager::sequenceReceived);
    QObject::connect(receiver.get(),&MAGlimpseReceiver::glimpseDataSignal,this,&MAItchManager::itchDataReceived);
    thread->start();
    threadList.push_back(thread);
}

This is the signal which is called from worker thread to main thread:

void MAGlimpseReceiver::glimpseDataReceived(ITradeMessagePtr tradeMessage) {
    if (tradeMessage != nullptr) {
        spdlog::debug("Glimpse Data Received For Market:{} Part:{} Type:{}",configuration.marketId,configuration.partId,tradeMessage->getType());
        emit glimpseDataSignal(tradeMessage.get(),int(configuration.marketId),configuration.partId);
    }
}

This is the slot in the main thread which receives the signal and try to use the virtual method

void MAItchManager::itchDataReceived(ITradeMessage* tradeMessage,int marketId,int partId) {
    spdlog::debug("Itch Data Received for Market: {} Part: {} Type:{}",marketId,partId,char(tradeMessage->getType()));
    if (tradeMessage->isValidMessage()) {
        auto itchPackage = std::make_shared<ItchPackage>();
        ItchMessage *itchMessage = tradeMessage->getItchMessage();
        itchPackage->market = MarketType (marketId);
        itchPackage->part = partId;
        itchPackage->itchMessage = itchMessage;
        if (callBack != nullptr) {
            callBack(itchPackage.get());
        }
    } else {
        spdlog::error("Unknown Trade Message Type:{}",tradeMessage->getType());
    }
}

And this is one of the example of base and derived classes which I'm trying to transfer to main thread. Base class:

class ITradeMessage {
public:

    ITradeMessage() {

    }

    ITradeMessage(const char* message) {

    }

    virtual ~ITradeMessage() {
    }

    ItchMessageType getType() const {
        return type;
    }

    virtual ItchMessage * getItchMessage() = 0;

    bool isValidMessage() const {
        return validMessage;
    }

protected:
    ItchMessageType type = ItchMessageType::Msg_None;
    bool validMessage = false;
};

using ITradeMessagePtr = std::shared_ptr<ITradeMessage>;

Derived Class:

class SecondMessage: public ITradeMessage {
public:
    SecondMessage() = default;
    SecondMessage(const char* message);
    SecondMessage(const SecondMessage& obj);
    ~SecondMessage() = default;

    friend std::ostream& operator<<(std::ostream&, const SecondMessage&);
    ItchMessage *getItchMessage();
};
Q_DECLARE_METATYPE(SecondMessage); //Compiler gives this warning but still compiles: Excess elements in struct initializer
using SecondMessagePtr = std::shared_ptr<SecondMessage>;
1
Impossible to say without a minimal reproducible example but, the code that emits the signal in MAGlimpseReceiver::glimpseDataReceived is passing the raw pointer managed by a shared_ptr across a queued connection. It's possible the shared_ptr has gone out of scope and deleted the managed memory before the receiving slot gets invoked.G.M.
As G.M. said, try to directly pass shared_ptr with your signal/slots. But with the shared_ptr object, not a pointer to the shared pointer! You will have to register std::shared_ptr<yourclass> with the Qt meta object system before this can work, i.e. by using qRegisterMetaType().markus-nm
If I try to pass the shared_ptr directly, qt doesnt trigger the signal/slot mechanism. Thats why I'm passing the raw pointer. I also think its because of shared_ptr too, but wasnt able to find a proper solution . I've also followed this link and applied all the steps but still getting the same error. doc.qt.io/qt-5/qtcore-threads-queuedcustomtype-example.htmltolgatanriverdi
What do you mean by " I try to pass the shared_ptr directly, qt doesnt trigger the signal/slot mechanism"? If that's the case then there should be an error message of some sort at the console. Essentially you need something like qRegisterMetaType<std::shared_ptr<ITradeMessage>>() to allow you to enqueue variables of that type.G.M.
it worked G.M thanks, if you can write this as answer I will accept it.tolgatanriverdi

1 Answers

0
votes

I've found the solution, thanks To @G.M

We need to register the type exactly how we are going to use it, such as:

qRegisterMetaType<std::shared_ptr<ITradeMessage>>()