zoukankan      html  css  js  c++  java
  • 基类子类在Qt信号量机制下的思考

    背景知识:

    基类 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方式将直接的消费方式注册到统一的地方,由一个地方统一调用。这样的话,各个线程的方法会排队执行,失去多线程的意义。

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

    爱恨难取舍。

  • 相关阅读:
    css知识点
    javascript 中闭包
    javascript 继承方法总结
    css滚动滚轮事件
    关于闭包的总结
    xpth xslt
    好的js函数
    自动化测试实施(4)
    自动化测试实施(5)
    自动化测试实施(3)
  • 原文地址:https://www.cnblogs.com/crazyghostvon/p/qtSignalSubbase.html
Copyright © 2011-2022 走看看