2016-08-19 90 views
0

在不同的线程的对象之间的槽基本上,我已经下一个代码:信号和Qt的

class serverTCP : public QObject 
{ 
     // Other methods... 

     signals: 
      void newInstructions(QJsonDocument jDoc); 

     public slots: 
      void responseObtained(QJsonDocument jDoc); 
} 

class gatherModbus : public QObject 
{ 
     // Other methods... 

     signals: 
      void responseReady(QJsonDocument jDoc); 

     public slots: 
      void executeInstruction(QJsonDocument jDoc); 
      void myprocess() { 
       while(true) 
       { 
        // Write and read Serial Port 
        // Save data in json 
       } 
      }; 
} 

void main(int argc, char *argv[]) 
{ 
     QCoreApplication a(argc, argv); 
     int netsNumber = 2; //In reality this is dynamic. It's only a example 
     serverTCP *server = new serverTCP; 
     gatherModbus * gather = new gatherModbus[netsNumber]; 
     QThread * threads = new QThread[netsNumber]; 

     // more necessary code... 

     for(int i = 0; i < netsNumber; i++) 
     { 
      gather[i].moveToThread(threads[i]); 

      QObject::connect(&server, SIGNAL(newInstructions(QJsonDocument)), 
          &gather[i], SLOT(executeInstruction(QJsonDocument))); 

      QObject::connect(&gather[i], SIGNAL(responseReady(QJsonDocument)), 
          &server, SLOT(responseObtained(QJsonDocument))); 

      QObject::connect(&threads[i], SIGNAL(start()), 
          &gather[i], SLOT(myprocess())); 

      // Other signals needed between the objects 'gather' and 'threads' 

      threads[i].start(); 
     } 

     a.exec(); 
} 

的问题是,对象“服务器”之间的连接'聚到一不工作。对象'server'和'main'函数在同一个线程中,但'gather'对象已经移动到其他线程中。

我该怎么做才能使两个对象能够正确通信?

我的目的是'服务器'必须能够发送信号到所有对象'聚集'有。在每个对象的“聚集”中,必须执行该槽并返回“服务器”响应(如果有的话)。

如果我将连接设置为Qt::DirectConnection类型的插槽,它与'main'函数和对象'server'在同一线程上运行,并且这些插槽对我没有兴趣。

任何帮助或建议,将不胜感激。

+0

我看不到'void myprocess()'在哪里调用。如果不是,请从代码示例中删除 – UmNyobe

+0

谢谢!我忘记将连接启动信号线程设置为“myprocess”方法。 – Jonathan

回答

0

所有的Qt文档。
首先,请阅读that
然后,如果你不满意,您可以使用QCoreApplication::postEvent()(更多的信息,你需要:here

两个信号/槽(QObject:connect())和QCoreApplication::postEvent()线程安全,并能解决您的问题。

因此事件和信号/插槽是完成相同事情的两个并行机制,通常一个事件将由外部实体(例如键盘,Mouswheel)生成并通过QApplication中的事件循环传递。一般情况下,除非你设置了代码,否则你不会生成事件。您可以通过QObject::installEventFilter()来过滤它们,或者通过覆盖相应的函数来处理子类对象中的事件。

信号和插槽更容易生成和接收,您可以连接任何两个QObject子类。它们是通过Metaclass处理的(查看你的moc_classname.cpp文件以获得更多信息),但是你将要生成的大多数类间通信可能会使用信号和插槽。信号可以立即传递或通过队列延期(如果您正在使用线程)可以生成信号

+2

OP可能缺少的位是QueuedConnection(和线程间自动连接)的工作,目标线程需要有事件循环。链接文档中的Mandlebrot示例可能是最好的示例。 –

0

您的演示代码似乎没问题。这就是我们组织当前项目的方式。如有必要,您最好提供更详细的代码来解释您的问题。

顺便说一句,在阅读您的兴趣之后,我会向您推荐QtConcurrent模块,它似乎更符合您的兴趣。

0

呃...你的代码不好。这是你的所有烦恼

void myprocess() { 
     while(true) 
     { 
      // Write and read Serial Port 
      // Save data in json 
     } 
}; 

的来源如果你想插槽newInstructionsresponseObtained插槽永远运行,myprocess不应该是一个无限循环。您需要:

  • 修改myprocess,使得一旦完成写入和读出目前掌握的数据,它完成
  • 有一个机制要知道,新的处理需要完成。例如,如果您使用QIODevice子类(套接字,输入流等),则您有信号QIODevice::readyRead(),它将通知您有新数据要从设备读取。我怀疑你的newInstructions应该这样做。
  • 这种机制连接到另一个呼叫myprocess,使处理再次开始

编辑:考虑您的意见,这是修改无限while循环没有过多修饰的方法。

void myprocess() { 
     make_one_processing_round(); 
     if(should_continue_processing()) 
     { 
      QMetaObject::invokeMethod(this, &gatherModbus::myprocess, Qt::QueuedConnection); 
     } 
}; 

QMetaObject::invokeMethod将在螺纹QEventLoop队列的后部调度用于执行此方法。这意味着其他插槽可以执行。

+0

gatherModbus的首要任务是从一些仪器modbus收集数据,并将数据保存在json中。这必须持续运行。 只有当serverTCP收到数据请求时,才会向gatherModbus对象发送一个信号。这些对象分析插槽中的消息。通常,只有一个gatherModbus对象必须响应。 我了解你的消息,我必须改变myprocess方法,因为有了这个无限循环系统无法处理事件循环。正确? 我阅读了Qt文档,但有时我不知道该怎么做。 – Jonathan

+0

正确。但不要使用while循环。你总是***有东西要读,写吗? – UmNyobe

+0

是的。每隔一段时间它必须从仪器读取数据,24小时必须在一年中的365天工作。 – Jonathan

0

我能解决我的问题,加上下一行“myprocess”方法的末尾:

QCoreApplication::processEvents(QEventLoop::AllEvents); 

这种方法的最终代码是这样的:

void myprocess() { 
      while(true) 
      { 
       // Write and read Serial Port 
       // Save data in json 

       // New line: 
       QCoreApplication::processEvents(QEventLoop::AllEvents); 
      } 
     }; 

这条线,我得到如果有的话,事件将被处理。我不知道它是否是最好的解决方案,但它的工作原理就像通缉一样。

感谢大家的帮助和解答。