问题描述:

当前有两个线程,T1, T2;

线程T1的run函数中,实例化出来了对象O1(里面有work()函数),T2(UI线程,也叫主线程)的run中实例化出来了O2(里面有string widgetModify(xx)函数);

work()函数中想调用O2的str = widgetModify(xx)函数,这就是一个跨线程调用的例子,跨线程写widget,需要传入参数,而且还需要获得返回值。这应该怎么做呢?

答案:

如果work()函数中直接 str = O2->widgetModify(xx);

那就会报错了,因为跨线程操作UI界面,会造成和主线程同时修改同一个界面的风险,qt是不允许的

但是如果是去修改(写)主线程中对象的数据(非界面),是没问题的;

或者是去读取主线程中的对象的数据,包括界面,都是没问题的。

所以,正确的方式如下:

方法1:信号和槽

O1中设置一个信号,连接到O2的一个槽函数。O1发射该信号,O2的槽函数则被队列方式触发。

从而达到O1调用O2中的函数的目的。

本质:抛了一个事件给O2的队列里。

方法2:QMetaObject::invokeMethod

O1直接通过调用invokeMethod函数,用字符串方式指明要调用对方哪个函数。

本质:仍然是抛了一个事件给O2的队列里。

方法3:QTimer::singleShot() 

O1自己启动一个单词定时器singleShot,要执行的槽函数填对方。

本质:仍然是抛了一个事件给O2的队列里。

方法4:去直接发射主线程的信号

O2里自己定义一个信号,连接到自己的槽函数(连接类型填AutoConnection(或者不填,因为这是默认值),使用这个值则连接类型会在信号发送时qt自己决定)。

O1里直接发射O2对象的该信号,从而O2的槽函数得到执行。

这个多线程同时发射主线程的该信号,也是没问题的。

本质:虽然发射信号操作是在线程T1里执行,而且被发射的信号还是O2对象里的信号,但是发射后,其实自动是队列形式连接的O2的槽函数。

总结:

方法1是最容易想到的,但是写起来有点儿麻烦。方式4是最好用的(我自己想出来的方法),关键点在于别的对象可以发射别人的信号(跨线程也行),此外,跨线程没有同时操作界面的操作都是可以的)。

对了,关于获取返回值,我还没有研究,因为还没有这个需求。