• 8303阅读
  • 7回复

Qt的辅助线程 [复制链接]

上一主题 下一主题
离线sbtree
 
只看楼主 倒序阅读 楼主  发表于: 2010-11-15
不知道大家注意到没有,在使用Qt库的时候,除了主线程之外,qt还默认地创建了多个辅助线程。
我这里用VS2008创建了一个空的Qt Application项目,在调试的时候观察到6个辅助线程,包括4个Win32 Thread和2个RPC Callback Thread,不理解的是Qt库为什么在一个任何事情都没有做的应用程序中开了这么多辅助线程? 这些线程到底都在做些什么事情?
从这个现象来看,Qt项目本身就不可能是单线程的,即使程序员没有创建任何自己的辅助线程。

带着这些疑问,尝试在Qt的源码中找答案:有了结果再来补充,也期待您的补充
windows 7 + VC++2008 + Qt4.5.2
离线sbtree
只看该作者 1楼 发表于: 2010-11-16
继续上面的例子,单步调试主函数
  1. #include "donothing.h"
  2. #include <QtGui/QApplication>
  3. int main(int argc, char *argv[])
  4. {
  5.     QApplication a(argc, argv); //1
  6.     donothing w; //2
  7.     w.show(); //3
  8.     return a.exec();//4
  9. }

在主函数,发现所有的辅助线程都是在第1行创建的,也就是说QApplication这个类的构造函数创建了这6个辅助线程
下一步就去看看QApplication这个类的构造函数
windows 7 + VC++2008 + Qt4.5.2
离线sbtree
只看该作者 2楼 发表于: 2010-11-16
这里突然想到一个问题,使用qt库建的项目都是从main函数开始的,那么qt是如何让C++运行期进入图形界面的呢?理论上讲支持图形窗口的应用程序都应该是从WinMain或者wWinMain开始的,估计还要看看qtmain的源代码了
windows 7 + VC++2008 + Qt4.5.2
离线dbzhang800

只看该作者 3楼 发表于: 2010-11-16
引用第2楼sbtree于2010-11-16 21:23发表的  :
这里突然想到一个问题,使用qt库建的项目都是从main函数开始的,那么qt是如何让C++运行期进入图形界面的呢?理论上讲支持图形窗口的应用程序都应该是从WinMain或者wWinMain开始的,估计还要看看qtmain的源代码了


不过,你这个理论应该不成立:
* http://hi.baidu.com/cyclone/blog/item/96624a90fb4ca081a977a4db.html
* http://hi.baidu.com/cyclone/blog/item/730334a8820911bcca130c23.html
离线sbtree
只看该作者 4楼 发表于: 2010-11-17
引用第3楼dbzhang800于2010-11-16 22:10发表的  :
不过,你这个理论应该不成立:
* http://hi.baidu.com/cyclone/blog/item/96624a90fb4ca081a977a4db.html
* http://hi.baidu.com/cyclone/blog/item/730334a8820911bcca130c23.html

不错,学习了。
其实我这也不是什么理论,说是理论上讲,都是从核心编程一书中的理解上来说的。而这个约定在qt中依然是成立的。下面基于VS2008进行一下简单地分析:

在我们创建qt控制台应用程序的时候,qt的应用程序模板为我们的连接器设定了SubSystem:Console,所以C++运行期在搜索应用程序的入口函数的时候自然就把main作为入口函数调用了,但是,你仍然可以看到模板把qtmain.lib连接到了项目中,只不过WinMain并没有作为入口函数被调用罢了,甚至根本就不会被调用。其实对于控制台应用程序,这里完全可以删除qtmain.lib。再看qt窗口应用程序,相应的默认设置是SubSystem:Windows,这就意味着连接器将把WinMain函数设为应用程序的入口函数,为什么我们能看到的和改写过的main函数起到作用了呢?原因就在于qtmain为我们设计好了WinMain函数,并且在其中把我们的main函数作为一个普通函数调用了而已。

从上面的分析可以看出,Qt的图形应用程序和控制台应用程序始终还是符合这个约定的,这里暂未考虑Unicode应用程序。至于控制台窗口出不出现,实际上是另一个问题,当然这也是跟连接器参数有关的,我未曾深入研究,可以参考张老师的连接。
[ 此帖被sbtree在2010-11-17 22:16重新编辑 ]
windows 7 + VC++2008 + Qt4.5.2
离线sbtree
只看该作者 5楼 发表于: 2010-11-17
贴上代码再进一步分析,源代码摘自qtmain_win.cpp
  1. int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prevInstance, LPSTR /*cmdParamarg*/, int cmdShow)
  2. {
  3.     QByteArray cmdParam = QString::fromWCharArray(GetCommandLine()).toLocal8Bit();
  4.     int argc = 0;
  5.     QVector<char *> argv(8);
  6.     qWinMain(instance, prevInstance, cmdParam.data(), cmdShow, argc, argv);
  7.     int result = main(argc, argv.data());
  8.      return result;
  9. }

重新编辑:原始代码有点长,所以把WinCE的部分删减了,只保留最主要的几行
[ 此帖被sbtree在2010-11-17 22:54重新编辑 ]
windows 7 + VC++2008 + Qt4.5.2
离线sbtree
只看该作者 6楼 发表于: 2010-11-18
  1. qWinMain(instance, prevInstance, cmdParam.data(), cmdShow, argc, argv);

这是一个很重要的函数,它完成Qt库的初始化工作
windows 7 + VC++2008 + Qt4.5.2
离线sbtree
只看该作者 7楼 发表于: 2011-04-12
今天终于有空搞清楚了,经过单步调试,发现所有这些辅助线程都是为多点触摸创建的。在实例化一个QApplication的时候其相应的QApplicationPrivate类也被初始化,这些线程就是在这个初始化函数里被创建的,看qapplication.cpp代码
  1. void QApplicationPrivate::initialize()
  2. {
  3. ...
  4.     if (qt_is_gui_used)
  5.         initializeMultitouch();
  6. }

initializeMultitouch()函数在我的机器上创建了6个线程(不包括该函数内部创建后又终止的)。从上面的代码可以看出,如果是图形界面的用用程序,该函数就被调用,该函数并没有对多点触摸设备的存在性进行检测,尽管我的机器不存在多点触摸设备,他还是为此创建了6个实际上无用的线程,或许什么时候Qt该改改这个函数了。

注:多点触摸设备的支持是从Qt4.6开始的,所以之前的版本应该不存在这样的问题
windows 7 + VC++2008 + Qt4.5.2
快速回复
限100 字节
 
上一个 下一个