基类子类在Qt信号量机制下的思考

摘要:
消费者订阅生产者的信号,然后消费子类。信号可以定义为:信号:void mysignal;此签名只能在单线程模式下使用。

背景知识:

基类 superClass

class superClass
{
public:
    superClass()
    {
        std::string m = "superClass()    " + std::to_string((long)this) + "
";
        std::cout << m << std::endl;
    }
    virtual ~superClass()
    {

        std::string m = "~superClass     " + std::to_string((long)this) + "
";
        std::cout << m << std::endl;
    }

    virtual void print() const
    {
        std::string m = "printsuperClass " + std::to_string((long)this) + "
" ;
        std::cout << m << std::endl;
    }
    virtual void setA(int v_) const {  }

private:
    int a = 0;
};

子类subClass

class subClass : public superClass
{
public:
    subClass():superClass(){ std::cout << "subClass()" << std::endl; }
    ~subClass()
    {
        std::cout << "~subClass" << std::endl;
    }

    void print()
    {
        std::cout << "subclass print " << std::endl;
    }

    void test()
    {
        std::cout << "test" << std::endl;
    }
};

生产者 生产子类,然后通过信号传递出去。消费者订阅生产者的信号,然后消费子类。

当生产者和消费者都在同一线程的时候:

mysignal(cn)

会被复制

复制次数 =消费者个数

mysignal(cn &)

不会被复制

mysignal(const cn &)

不会被复制

by value  same thread

superClass()    140737488346832
printsuperClass 140737488346416
~superClass     140737488346416
printsuperClass 140737488346416
~superClass     140737488346416
printsuperClass 140737488346416
~superClass     140737488346416
~superClass     140737488346848
~superClass     140737488346832

当生产者和消费者均在不同线程时:

mysignal(cn)

会被复制

复制次数 =消费者个数*2

mysignal(cn &)

不可用于多线程

mysignal(const cn &)

会被复制

复制次数=消费者个数

by value different

superClass()    140737488346832
printsuperClass 140737018587504
~superClass     140737018587504
printsuperClass 140737010194800
~superClass     140737010194800
printsuperClass 140737001802096
~superClass     140737001802096
~superClass     9651648
~superClass     9498640
~superClass     9666912
~superClass     140737488346848
~superClass     140737488346832


解决方案1: 

生产者和消费者在同一线程,那么只能按照生产一个消费一个的模式工作。

Signal的定义可以为:

signals:
void mysignal(superClass &);

该签名只能用于单线程模式。

多线程模式下:

signals:
void mysignal(superClass);

该模式下,消费者端代码如下:

public slots:
    void consume(superClass sc)
    {
        subClass & sub = (subClass &)(sc);
        sub.print();
    }

或者

signals:
    void mysignal(const superclass &);

该模式下,消费者端代码如下:

public slots:
    void consume(const superClass & sc)
    {
        superClass temp = sc;
        subClass & sub = (subClass &)(temp);
        sub.print();
}

此时,sub调用的是父类的print方法。

解决方案二:

在子类中添加一个通过父类来构造子类的构造方法:

class subClass : public superClass
{
public:
    subClass():superClass(){ std::cout << "subClass()" << std::endl; }

    subClass(const superClass & s):subClass()
    {
        std::cout << "construct subClass from superClass()" << std::endl;
    }

    ~subClass()
    {
        std::cout << "~subClass" << std::endl;
    }

    void print() override
    {
        std::cout << "subClass" << a << std::endl;
    }

    void setA(int v_) { a = v_; }

    void test()
    {
        std::cout << "test" << std::endl;
    }

private:
    int a = 0;
};

生产者如下生产:

    void produce()
    {
        subClass sub;
        sub.setA(100);
        emit mysignal(sub);
    }

消费者如下消费:

    void consume(const superClass & sc)
    {
        subClass sub = sc;
        sub.print();
    }

但此时subClass中的a信息已经丢失。

解决方案三:

改用指针,方法签名为:

signals:
void mysignal(superClass *);

生产者如下生产:

    void produce()
    {
        subClass * sub = new subClass();
        sub->setA(100);
        emit mysignal(sub);
    }

消费者如下消费:

    void consume(superClass * sc)
    {
        subClass * sub = dynamic_cast<subClass *>(sc);
        sub->print();
    }

但是在有多个消费者的时候,

    connect(&p, SIGNAL(mysignal(superClass *)), &c, SLOT(consume(superClass *)));
    connect(&p, SIGNAL(mysignal(superClass *)), &c2, SLOT(consume(superClass *)));

没有消费者适合删除指针。必然导致内存泄漏。一旦有消费者删除了指针,则其他未消费的消费者将崩溃。这样的设计有一个隐患,一个消费者的恶意代码可以搞垮其他消费者。

解决方案四:

放弃QT 信号机制,自己实现ResultHandler,所有的消费者通过register方式将直接的消费方式注册到统一的地方,由一个地方统一调用。这样的话,各个线程的方法会排队执行,失去多线程的意义。

综上,放弃父类子类设计方式。由统一一个类来实现所有功能。但是传递对象有效率问题,因为有多少个消费者,就会复制多少份对象。

爱恨难取舍。

免责声明:文章转载自《基类子类在Qt信号量机制下的思考》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇highcharts配置的效果如下基于c#发送Outlook邮件(仅SMTP版本)下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章