2012-08-17 55 views
0

我有几个客户端GUI窗口都来自QMainWindow。每个窗口都可能执行不同的任务,但都是从中央缓存请求数据,实现为QThreadQt 4.7发送信号到特定的线程

所有客户端连接到数据缓存中的相同slot,然后发出signal s提示数据缓存执行某些操作。数据缓存中的signal被排队,因此数据缓存一次只能处理一件事情。

当数据缓存完成时,它需要通知正确的客户端它正在做的事情已经完成。我的直接想法是发出一个signal给请求客户关于完成。这意味着连接到一个特定的客户端slot,然后发出一个signal它。

我必须做连接然后断开连接到客户端吗?我知道QObject::sender()函数来获取供应商。是否有某种方式仅向发送者(客户端)发送信号?或者有没有其他的方式来做到这一点?

+0

- 从客户端对象或数据缓存中调用'QObject :: connect'以形成客户端和数据缓存之间的链接? - 这个问题的标题是什么意思 - 你的应用程序创建的具体线程是什么? - 客户端对象在接收到“数据缓存完成”信号时需要做什么,我指的是客户端需要从缓存中检索多少数据? – sjwarner 2012-08-17 17:49:30

+0

澄清@sjwarner评论。我从客户端对象调用QObject :: connect,即QMainwindow派生对象。我一直假设它们中的每一个代表一个单独的GUI线程。返回的数据量取决于数据缓存的要求,数量可能很少或很大。我正在使用指向数据缓存的指针来访问这些数据。正在被访问的数据一旦被初始化就是静态的,因此没有锁定机制。到目前为止,我没有任何冲突。 – bogflap 2012-08-22 14:14:37

回答

0

可能有更简单的方法可以解决您的问题。例如,我会考虑研究QtConcurrent框架。或者,您也可以重新设计您的设计,以便客户端首先连接到缓存上的“完成”信号,然后再请求缓存执行任何操作。如果没有这些,您可能还会考虑依靠QMetaObject::invokeMethod函数(用于客户端或缓存)。这个函数允许你使用任意的泛型参数(以线程安全的方式)在任意QObject上调用任意方法(假设你有一个指向它的指针)。

如果您使用QMetaObject::invokeMethod方法,您应该注意一些缺点。首先,您必须使用其字符串名称调用该方法,这意味着您不会在编译时发现是否使用了错误的名称。其次,由于您的客户端与中央缓存具有不同的线程关联性,因此当缓存调用方法时,客户端可能会被销毁(可能对您而言,这对您来说不会有问题) 。最后,你可能不希望你的缓存知道它必须在它的客户端上执行的方法的名字。

我没有办法绕过第一个缺点(我不确定这是否会在即将到来的Qt 5.0版本中以不同方式处理)。至于第二个和第三个问题,我建议创建封装到一个方法的引用一个对象 - 像下面的东西:

class MethodReference 
{ 
    MethodReference(QObject* object, const QString& methodName); 

    ... 

    bool invoke(QGenericArgument val0 = QGenericArgument(), 
       QGenericArgument val1 = QGenericArgument(), 
       ... 
       QGenericArgument val9 = QGenericArgument()); 

private: 
    QPointer<QObject> mObject; 
    QString mMethod; 
}; 

你会然后把这个对象传递给你的缓存从客户端。缓存然后调用此对象的调用。

请注意QPointer的使用 - 这为您提供了一种线程安全的方法,用于在尝试调用其上的方法之前检查对象是否已被销毁。由于我之前完成了这个工作,我还会告诉你,4.8之前的Qt版本有一个bug in QPointer,这会导致多线程环境中的崩溃。如果你想这样做,请使用更新版本的Qt。

我希望这很清楚。

+0

谢谢@RA。到目前为止,我不得不承认元对象子系统对我来说有点神秘。我尽可能少地使用它,但看到你的答案促使我再次仔细观察它。 QMetaObject :: invokeMethod让我想起了Java,这真的很有趣 – bogflap 2012-08-22 14:22:19