• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            隨筆-1  評論-10  文章-0  trackbacks-0

            第一回 Signal和Slot是同步的還是異步的?

              我們知道Qt以他的signal和slot機制獨步天下。但大家在用的時候有沒有注意過,signal和slot之間是異步的,還是同步的呢?為此我問過不少使用Qt的道友。有人說是同步的,有人說是異步的,也有人說要看當時你的人品。:( #$%^&*

              為此貧道,特別做了以下幾個測試:

                 First,在main()主函數里,設置兩個基于QObject為父類的對象a和b,a觸發signal,b接受signal。請看具體案例:

                

             1 class MyTestA : public QObject
            2 {
            3 Q_OBJECT
            4 public:
            5 void emitSignal()
            6 {
            7 signalMyTestA();
            8 }
            9
            10 public slots:
            11 void slotMyTestA()
            12 {
            13 qDebug()<<"slotMyTestA is called.";
            14 }
            15 signals:
            16 void signalMyTestA();
            17 };
            18
            19 class MyTestB : public QObject
            20 {
            21 Q_OBJECT
            22 public slots:
            23 void slotMyTestB()
            24 {
            25 qDebug()<<"slotMyTestB is called.";
            26 }
            27 signals:
            28 void signalMyTestB();
            29 };
            30
            31 int main(int argc, char *argv[])
            32 {
            33 QApplication app(argc, argv);
            34
            35 MyTestA a;
            36 MyTestB b;
            37 QObject::connect(&a,SIGNAL(signalMyTestA()),&b,SLOT(slotMyTestB()));
            38
            39 a.emitSignal();
            40
            41 return app.exec();
            42 }

            在slotMyTestB的函數里打個斷點,看一下調用堆棧(call stack)。

            是同步調用的,某些道友開始拈胡微笑,實踐出真知啊。

            此時只見東方黑云滾滾,電閃雷鳴,又有道友開始度劫了。突然一度劫道友橫眉冷對,拿起拂塵刷刷的改寫了上面的代碼。只見此道友把a對象挪到了一個新線程中(MyTestC創建的),而b對象仍然在主線程中。然后a對象觸發信號。

            class MyTestA : public QObject
            {
                Q_OBJECT
            public:
                void emitSignal()
                {
                    signalMyTestA();
                }
            public slots:
                void slotMyTestA()
                {
                    qDebug()<<"slotMyTestA is called.";
                }
            signals:
                void signalMyTestA();
            };
            class MyTestB : public QObject
            {
                Q_OBJECT
            public slots:
                void slotMyTestB()
                {
                    qDebug()<<"slotMyTestB is called.";
                }
            signals:
                void signalMyTestB();
            };
            extern MyTestB *g_pMyTestB;
            class MyTestC : public QThread
            {
                Q_OBJECT
            public:
                void run()
                {
                    MyTestA a;
                    connect(&a,SIGNAL(signalMyTestA()),g_pMyTestB,SLOT(slotMyTestB()));
                    a.emitSignal();
                    exec();
                }
            public slots:
                void slotMyTestC()
                {
                    qDebug()<<"slotMyTestC is called.";
                }
            signals:
                void signalMyTestC();
            };
            class MyTest : public QDialog
            {
                Q_OBJECT
            public:
                MyTest(QWidget *parent = 0, Qt::WFlags flags = 0);
                ~MyTest();
            private:
                Ui::MyTestClass ui;
            };
            ////////////////////////////////////////////////
            MyTestB *g_pMyTestB = NULL;
            int main(int argc, char *argv[])
            {
                QApplication app(argc, argv);
                MyTestB b;
                g_pMyTestB = &b;
                MyTestC c;
                c.start();
                return app.exec();
            }
            

            說時遲,那時快。在一道紫雷劈下之際,按下了F5。只見,此時的調用堆棧顯示,

            奇跡出現了,居然變成異步調用了。只見東方天空萬道金光射下,在陣陣仙樂聲中,傳來朗朗之聲:"貧道塵事已了,再無牽掛"。

            難道Qt真的是靠人品的,或者Qt莫不是也是修仙道友,不日也將飛升。

            在吾等眾人膜拜加疑惑之時,只見飛升前輩,留下一條偈語。內事不決問百度,外事不決問谷歌。

            吾等眾人立刻搜尋,恍然大物。

            原來signal和slot是異步調用還是同步調用,取決于對connect的設定。其實connect還有一個參數(Qt::ConnectionType),是它決定了是同步還是異步。以下是ConnectionType的定義

            只不過,平常它有一個默認值Qt::AutoConnection,我們忽略了它。這時有道友問道,為何在AutoConnection模式下,有時是同步,有時是異步,莫非Auto就是人品代名詞。

            非也,其實Auto是這樣規定的,

            當sender和receiver在同一線程時,就是同步模式,而在不同線程時,則是異步模式。

            眾人皆曰善。

            就在眾人彈冠相慶之時,突然一道類似眼鏡發出的寒光閃過,一個黑影漸漸清晰了起來。

            他居然就是..................

            青春永駐,十二年如一日的柯南君,他招牌式的磁性聲音給眾道友一晴天霹靂,“諸位以為這就是全部的真相嗎?”

            接著他刷刷的又改寫了代碼,在主線程中生成a,b兩個對象,而a對象在新線程(MyTestC創建的)中觸發信號。

             

            class MyTestA : public QObject
            {
                Q_OBJECT
            public:
                void emitSignal()
                {
                    signalMyTestA();
                }
            public slots:
                void slotMyTestA()
                {
                    qDebug()<<"slotMyTestA is called.";
                }
            signals:
                void signalMyTestA();
            };
            class MyTestB : public QObject
            {
                Q_OBJECT
            public slots:
                void slotMyTestB()
                {
                    qDebug()<<"slotMyTestB is called.";
                }
            signals:
                void signalMyTestB();
            };
            extern MyTestB *g_pMyTestB;
            extern MyTestA *g_pMyTestA;
            class MyTestC : public QThread
            {
                Q_OBJECT
            public:
                void run()
                {
                    g_pMyTestA->emitSignal();
                    exec();
                }
            public slots:
                void slotMyTestC()
                {
                    qDebug()<<"slotMyTestC is called.";
                }
            signals:
                void signalMyTestC();
            };
            /////////////////////////////////////////////
            MyTestB *g_pMyTestB = NULL;
            MyTestA *g_pMyTestA = NULL;
            int main(int argc, char *argv[])
            {
                QApplication app(argc, argv);
                MyTestA a;
                g_pMyTestA = &a;
                MyTestB b;
                g_pMyTestB = &b;
                QObject::connect(&a,SIGNAL(signalMyTestA()),&b,SLOT(slotMyTestB()));
                MyTestC c;
                c.start();
                return app.exec();
            }
            

             

            在眾人疑惑的眼光中,此君淡定的按下了F5。只見調用堆棧(call stack)顯示

            眾人皆驚呼,“Impossible”。a和b明明是屬于一個線程的,為何會異步調用。此時我們熟悉的語錄,又在耳邊回響,是"我相信真相只有一個!!!"這句話嗎?No,只見柯南君,優雅地揮了揮手指,"Nothing impossible",從口中緩緩滑出。

            。眾人皆撲街,“有屁快放”。

            此時柯南君緩緩從口袋中,摸出一張紙,拋向空中,然后轉身離去。只見隨風飄落的紙面上面摘錄了這么一段Qt源代碼,在Auto模式下,如果要同步調用,不僅要求sender和receiver是同一線程,而且sender觸發的時候,所在的線程也要和receiver一致。

             // determine if this connection should be sent immediately or
                        // put into the event queue
                        if ((c->connectionType == Qt::AutoConnection
                             && (currentThreadData != sender->d_func()->threadData
                                 || receiver->d_func()->threadData != sender->d_func()->threadData))
                            || (c->connectionType == Qt::QueuedConnection)) {
                            queued_activate(sender, signal_absolute_index, c, argv ? argv : empty_argv);
                            continue;
                        } else if (c->connectionType == Qt::BlockingQueuedConnection) {
                            blocking_activate(sender, signal_absolute_index, c, argv ? argv : empty_argv);
                            continue;
                        }

            摘自qobject.cpp

            z眾人皆驚,原來在Auto模式下,如果sender的觸發時所處的線程和receiver不同,也會是異步調用。此時道友齊聲向柯南喊道“這是全部的真相了嗎”?柯南轉過頭來笑而不語,漸漸又消失在黑暗中。“有多少無恥可以重來”漂上了眾人的心頭。望著遠處的雨后陽光,一個大大的問號也出現在眾人頭頂,"Qt你到底有多無恥???"。眾人又陷入了沉思。

            欲知后事如何,請聽下回分解。

             

            此篇已在CNBLOG同時發布

             

             

             

             

             

             




            posted on 2011-08-26 10:41 櫻桃小錘子 閱讀(12944) 評論(10)  編輯 收藏 引用

            評論:
            # re: Qt那點事兒(一) 2011-08-26 12:25 | 飯中淹
            磁性的柯南。。。看著他變小的長大的我們這一代。  回復  更多評論
              
            # re: Qt那點事兒(一) 2011-08-26 13:35 | tinyms
            Sign是異步的,slot是同步的,前者是消息,后者僅僅是回調  回復  更多評論
              
            # re: Qt那點事兒(一) 2011-08-26 14:27 | 櫻桃小錘子
            @tinyms
            Sign是異步的,slot是同步的>>何解,請賜教
              回復  更多評論
              
            # re: Qt那點事兒(一) 2011-08-26 15:23 | 他她女鞋
            感覺還是挺繁雜的。  回復  更多評論
              
            # re: Qt那點事兒(一)[未登錄] 2011-08-26 17:20 | cc
            我弟,你敢說的簡單點嗎  回復  更多評論
              
            # re: Qt那點事兒(一) 2011-08-28 14:12 | mos
            搞這么復雜,真不如boost::signal  回復  更多評論
              
            # re: Qt那點事兒(一) 2011-08-29 09:45 | zuhd
            哥 你的文筆太有愛了 不懂qt
            我是來看小說的  回復  更多評論
              
            # re: Qt那點事兒(一)[未登錄] 2011-08-29 11:19 | 姚冬
            如果比較下常用的幾種 signal/slot實現的話,我覺得Qt的實現是最好的。

            boost的signal/slot 有一個很嚴重的問題,就是會導致編譯非常慢,你寫個小測試程序是不會感覺到的,如果在幾十個文件中使用的話,編譯時間會成倍增長,即使用并行編譯也是慢。都是模板搞的,boost的泛型用得太花哨了。

            Qt則完全沒有這個問題,而且執行效率也還可以。  回復  更多評論
              
            # re: Qt那點事兒(一) 2011-08-30 13:52 | uestc001@163.com
            文筆不錯  回復  更多評論
              
            # re: Qt那點事兒(一) 2011-11-07 21:54 | 渡劫導游
            某學過半個月Qt的導游落果  回復  更多評論
              
            国产成人综合久久综合| 日韩电影久久久被窝网| 久久精品国产亚洲AV无码娇色| 亚洲AV日韩精品久久久久久久| 成人妇女免费播放久久久| 99久久精品免费观看国产| 久久天天躁狠狠躁夜夜2020| 久久久精品人妻一区二区三区蜜桃 | 91精品国产高清91久久久久久| 久久99国产精品二区不卡| 亚洲午夜精品久久久久久浪潮| 色综合久久久久无码专区 | 亚洲国产日韩欧美久久| 亚洲色大成网站www久久九 | 亚洲精品乱码久久久久久不卡| 久久天堂AV综合合色蜜桃网| 青春久久| 精品久久人人做人人爽综合| 国产精品久久久久AV福利动漫| 久久综合九色综合欧美就去吻| 97r久久精品国产99国产精| 中文字幕日本人妻久久久免费| 国产精品一区二区久久精品无码| 久久久久久亚洲Av无码精品专口| 亚洲欧美日韩精品久久亚洲区| 久久99国产精品久久久| 欧美喷潮久久久XXXXx| 思思久久99热免费精品6| 精品水蜜桃久久久久久久| 久久se精品一区二区| 久久人人爽人人爽人人片av高请| 国内精品久久久久影院亚洲| 久久男人中文字幕资源站| 国产毛片久久久久久国产毛片| 久久精品这里热有精品| 77777亚洲午夜久久多喷| 久久AV高清无码| 99久久精品午夜一区二区| 国产精品一久久香蕉产线看| 国产精品欧美久久久天天影视| 久久精品麻豆日日躁夜夜躁|