问题描述:
当前有两个线程,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是最好用的(我自己想出来的方法),关键点在于别的对象可以发射别人的信号(跨线程也行),此外,跨线程没有同时操作界面的操作都是可以的)。文章来源:https://uudwc.com/A/BnZG4
对了,关于获取返回值,我还没有研究,因为还没有这个需求。文章来源地址https://uudwc.com/A/BnZG4