Signals and Slots AcrossThreads
Qt支持了几种信号--槽的连接方式:
1. Auto Connection (默认):如果如果信号的发送方与接收方是处于同一个线程,这个连接就是 Direct Connection,否则就跟 Queued Connection一样。
2. Direct Connection :当信号发出之后,槽会立即被调用。槽函数是在信号发送方的线程中运行的,不需要接收方的线程。
3. Queued Connection:当控制权回到接收方线程时调用槽函数。槽函数是在接收方的线程中运行的。
4. Blocking Queued Connection :调用方式跟 Queued Connection一样,区别在于,当前线程会被阻塞直到槽函数返回。
5. Unique Connection :这种方式跟 Auto Connection一样,但是只有当不存在一个相同的连接时才会创建一个连接。如果已经存在相同的连接,则不会创建连接,connect()返回false。
可以在connect()添加参数指定连接类型。需要注意的一点是:如果信号发送方和接收方处于不同的线程,而且接收方线程运行着一个事件循环,此时用Direct Connection是不安全,原因跟调用一个对象的函数,而这个对象处于另外的线程,那样的调用是不安全。
QObject::connect() 本身是线程安全的。
下面通过结果例子验证一下:
class Receiver:publicQObject
{
Q_OBJECT
public:
voidsendmes()
{
emitemitSignal("emit message from A To B");
}
Receiver()
{
}
protected slots:
voidmessageSlot(QString mes)
{
qDebug()<<mes;
}
signals:
voidemitSignal(QString mes);
private:
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Receiver objA,objB;
QObject::connect(&objA,SIGNAL(emitSignal(QString)),&objB,SLOT(messageSlot(QString)));
qDebug()<<"beforeemitsignal ";
objA.sendmes();
qDebug()<<"afteremitsignal ";
returna.exec();
}
objA,objB;出于同一个线程,所以connect的连接类型是Direct Connection
由输出我们可以看出执行顺序,
如果我们写了两句连接:
QObject::connect(&objA,SIGNAL(emitSignal(QString)),&objB,SLOT(messageSlot(QString)));
QObject::connect(&objA,SIGNAL(emitSignal(QString)),&objB,SLOT(messageSlot(QString)));
就会相应的有两句消息输出:
如果指定了连接类型Qt::UniqueConnection ,就会只有一句消息输出了。
QObject::connect(&objA,SIGNAL(emitSignal(QString)),&objB,SLOT(messageSlot(QString)),Qt::UniqueConnection );
QObject::connect(&objA,SIGNAL(emitSignal(QString)),&objB,SLOT(messageSlot(QString)),Qt::UniqueConnection);
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QThread *thread = new QThread;
thread->start();
Receiver objA,objB;
objB.moveToThread(thread);
QObject::connect(&objA,SIGNAL(emitSignal(QString)),&objB,SLOT(messageSlot(QString)) );
qDebug()<<"beforeemitsignal ";
objA.sendmes();
qDebug()<<"afteremitsignal ";
returna.exec();
}
如果我们把objB放到另外的线程,connect的连接类型应该是Queued Connection 。
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QThread *thread = new QThread;
thread->start();
Receiver objA,objB;
objB.moveToThread(thread);
QObject::connect(&objA,SIGNAL(emitSignal(QString)),&objB,SLOT(messageSlot(QString)) ,Qt::BlockingQueuedConnection);
qDebug()<<"beforeemitsignal ";
objA.sendmes();
qDebug()<<"afteremitsignal ";
returna.exec();
}