关于qt主线程和次线程的一点疑惑

aobenhaimo 2012-05-17 11:26:38
最近比较关注qt的多线程。看了http://apps.hi.baidu.com/share/detail/23550552 这篇文章后,才发现自己以前对qt的多线程认识是错的!比如自己写一个qthread子类,除了run()这个函数是在次线程执行的,其它函数都是在主线程被调用的,因为qthread类就是一个qobject,它是在主线程创建的,自然它的那些非run()函数以及各种数据成员都属于主线程。
我自己写了个小的测试程序,分别在主线程中实例化QThread子类对象、QObject子类对象、以及一个自己定义的基类对象,然后在这些对象构造函数里分别打印当前的QthreadId。在主线程中定义的对象自然应该和主线程id一致,可是结果却并非如此:
Object/ObjectNew是我定义的两个继承自QObject类的子类,它们都在各自的构造函数里打印当前线程的id,比如

Object::Object(QObject *parent) :
QObject(parent)
{
cout<<"obj construct:"<<QThread::currentThread()<<endl;
}

Worker类继承自QThread类,我分别让它在构造函数和run()函数中打印当前的threadid。

Worker::Worker(QObject *parent) :
QThread(parent)
{
cout<<"work thread construct:"<<QThread::currentThreadId()<<endl;
}
void Worker::run()
{
cout<<"thread running:"<<QThread::currentThreadId()<<endl;
exec();
}

然后还定义了一个无父类的类A,让它在构造函数里打印当前线程id:

A::A()
{
cout<<"A instance construct"<<QThread::currentThreadId()<<endl;
}

最后我在main函数中实例化这些类的对象
[code=C/C++]
int main(int argc, char *argv[])
{

QCoreApplication a(argc, argv);
cout<<"main thread:"<<QThread::currentThreadId()<<endl;
Worker worker;
worker.start();
ObjectNew objnew;
Object obj;
A b;
return a.exec();
}
运行结果截图:

其中main函数所在的线程id(主线程id)和worker、A类的对象所打印的线程id一致,都是0Xa80,worker在调用start()后会运行run(),此时打印的线程id是次线程id 0X140。不过让我不解的是为什么继承自QObject的两个对象打印出的线程id却和主线程id不一样,是0X3b29f8?难道这两个类的对象不是在主线程创建的吗?求达人解答下
...全文
1581 15 打赏 收藏 转发到动态 举报
写回复
用AI写文章
15 条回复
切换为时间正序
请发表友善的回复…
发表回复
weiwei22844 2013-04-26
  • 打赏
  • 举报
回复
大牛们能解释一下为什么不推荐run的方式吗?
zhu_xz 2012-06-11
  • 打赏
  • 举报
回复
是的,把工作丢给run来作,这样的做法是可以的,但是不推荐
aobenhaimo 2012-06-11
  • 打赏
  • 举报
回复


看这个文章:http://labs.qt.nokia.com/2010/06/17/youre-doing-it-wrong/
这样的做法不错,但并不推荐 ;)
[/Quote]
恩,我也是看了这篇文章,才意识到自己以前对qthread理解错了。这篇文章推荐的方法比把所有的工作都丢给run函数来处理要好太多了。另外,你说的这样的做法不错,但并不推荐,我没理解错的话,应该指的就是把工作丢给run的那种吧
zhu_xz 2012-05-18
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 的回复:]

线程用到的东西最好在run里面创建,这样,销毁的线程的时候会吧创建的对象全部销毁。
[/Quote]
看这个文章:http://labs.qt.nokia.com/2010/06/17/youre-doing-it-wrong/
这样的做法不错,但并不推荐 ;)
xiebin133 2012-05-18
  • 打赏
  • 举报
回复
额。一般我多会继承QThread,然后在写个类在QThread中创建,然后将这两个类通过信号与槽关联起来。看来以前太肤浅了。
zhu_xz 2012-05-18
  • 打赏
  • 举报
回复
[Quote=引用 10 楼 的回复:]

moveToThread 这个方法我基本上没用过,据说这个方法QT并不推荐用。
[/Quote]
Qt推荐使用moveToThread()
因为QThread是用来表示线程的类,而不是表示那些逻辑应该在线程内执行的类
xiebin133 2012-05-18
  • 打赏
  • 举报
回复
moveToThread 这个方法我基本上没用过,据说这个方法QT并不推荐用。
xiebin133 2012-05-17
  • 打赏
  • 举报
回复
线程用到的东西最好在run里面创建,这样,销毁的线程的时候会吧创建的对象全部销毁。
zhu_xz 2012-05-17
  • 打赏
  • 举报
回复
> 另外,“函数和数据成员本身并不“属于”某一个具体的线程”,请允许我稍微打个问号,我看qt官方文档说,"A QObject instance is said to live in the thread in which it is created. Events to that object are dispatched by that thread's event loop. ”。我觉得这应该是说一个object对象还是有自己所归属的线程的,只不过它的数据和函数可以在其它线程里被访问(但是这样不能保证安全,比如socket或者timer等,在另一个线程里访问这些对象会发生错误)

我的意思是,这个对象不会因为线程的销毁而自动销毁(当然除非你设置了相应的parent-child关系)

在Qt里面,如果对象A位于线程B里面,那通过auto connect触发的slot都会在线程B上执行
至于你说的安全访问的问题,其实是线程安全的问题,因为绝大多数的Qt类并没有用mutex等对代码做保护
xiebin133 2012-05-17
  • 打赏
  • 举报
回复
其实你在run里面创建一个对象,然后用信号关联一个槽,你会发现信号发来的时候,槽是在线程里面执行的,一般多是这么做的,并不是把代码全写到run里面去。
aobenhaimo 2012-05-17
  • 打赏
  • 举报
回复
恩,发现了,两个类里的构造函数我是拷贝其中一个的,结果第一个写错了第二个也错了。多谢。
另外,“函数和数据成员本身并不“属于”某一个具体的线程”,请允许我稍微打个问号,我看qt官方文档说,"A QObject instance is said to live in the thread in which it is created. Events to that object are dispatched by that thread's event loop. ”。我觉得这应该是说一个object对象还是有自己所归属的线程的,只不过它的数据和函数可以在其它线程里被访问(但是这样不能保证安全,比如socket或者timer等,在另一个线程里访问这些对象会发生错误)
aobenhaimo 2012-05-17
  • 打赏
  • 举报
回复
天果然是写错了,一个类写错了结果拷贝到另一个类也是错的,汗啊,我还以为QObject有什么特别的呢,多谢
zhu_xz 2012-05-17
  • 打赏
  • 举报
回复
> 因为qthread类就是一个qobject,它是在主线程创建的,自然它的那些非run()函数以及各种数据成员都属于主线程

QThread是用来表示线程的一个类,而不是线程自身
函数和数据成员本身并不“属于”某一个具体的线程,而是在哪一个线程中被调用/访问


注意:
1)QThread::currentThread()是返回当前运行的那个QThread对象的指针
2)QThread::currentThreadId()是返回当前运行的那个线程的ID

你的两个从QObject继承来的类是打印的currentThread,当然和currentThreadId不一样啊
xiebin133 2012-05-17
  • 打赏
  • 举报
回复
cout<<"obj construct:"<<QThread::currentThread()<<endl; 你这句话是不是打错了,应该是QThread::currentThreadId()吧。

16,216

社区成员

发帖
与我相关
我的任务
社区描述
Qt 是一个跨平台应用程序框架。通过使用 Qt,您可以一次性开发应用程序和用户界面,然后将其部署到多个桌面和嵌入式操作系统,而无需重复编写源代码。
社区管理员
  • Qt
  • 亭台六七座
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧