C++中的线程问题

roc*_*oll 3 c++ qt multithreading qt4

我在许多热门论坛上都提到了这个问题但没有具体的回应.我的应用程序使用串行通信与外部系统连接,每个外部系统都有自己的接口协议.从系统接收的数据显示在Qt 4.2.1中制作的GUI上.

应用程序的结构就是这样

  1. 当应用程序开始时,我们有一个登录页面,可以选择四个模块.这是作为maindisplay类实现的.四个模块中的每一个本身都是一个单独的类.这里涉及的模块是动作类,负责从各种系统收集和显示数据.

  2. 用户身份验证使他/她进入操作屏幕.动作屏幕类的构造函数执行,除了普通的初始化之外,它还启动单个系统线程,这些线程实现为单例.

每个系统协议都实现为以下形式的单例线程:

class SensorProtocol:public QThread {    
    static SensorProtocol* s_instance;
    SensorProtocol(){}
    SensorProtocol(const SensorProtocol&);
    operator=(const SensorProtocol&);

public:
    static SensorProtocol* getInstance();
    //miscellaneous system related data to be used for
    // data acquisition and processing
};
Run Code Online (Sandbox Code Playgroud)

在实现文件*.cpp中:

SensorProtocol* SensorProtocol::s_instance=0;
SensorProtocol* SensorProtocol::getInstance()
{
   //DOUBLE CHECKED LOCKING PATTERN I have used singletons
   // without this overrated pattern also but just fyi  
   if(!s_instance)
   {
       mutex.lock();
       if(!s_instance) 
           s_instance=new SensorProtocol();
       mutex.unlock();
   } 
}
Run Code Online (Sandbox Code Playgroud)

运行功能的结构

while(!mStop)
{
  mutex.lock()
  while(!WaitCondition.wait(&mutex,5)
  {
      if(mStop)
      return;    
  }

  //code to read from port when data becomes available
  // and process it and store in variables
  mutex.unlock();
}
Run Code Online (Sandbox Code Playgroud)

在动作屏幕类中,我使用sigaction和saio定义了一个InputSignalHandler.这是一个函数指针,一旦数据到达任何串行端口就会被激活.

它是一个全局函数(我们无法更改它,因为它特定于Linux),它仅用于比较数据已到达的串行端口的文件描述符和传感器系统的fd,如果找到匹配WaitCondition.wakeOne在该线程上调用它,它出来等待并读取和处理数据.

在操作屏幕类中,各个线程以启动方式启动SensorProtocol::getInstance()->start().

每个系统的协议都具有发送数据的帧速率.基于这一事实,在操作屏幕中,我们设置更新计时器以超时协议的刷新率.当这些定时器超时时,调用操作屏幕的UpdateSensorProtocol()函数

connect(&timer, SIGNAL(timeout), this,SLOT(UpdateSensorProtocol()));
Run Code Online (Sandbox Code Playgroud)

这抓住了传感器单例的实例

SensorProtocol* pSingleton=SensorProtocol::getInstance();
if(pSingleton->mUpdate)
{
    //update data on action screen GUI
   pSingleton->mUpdate=false;  //NOTE : this variable is set to
                               // true in the singleton thread
                               // while one frame is processed completely
}
Run Code Online (Sandbox Code Playgroud)

对于使用单例实例的所有用法SensorProtocol::getInstance().鉴于上述情况,无论我做什么改变,我的一个协议都会挂起.

挂起发生在使用UpdateSensorProtocol()显示数据时如果我ShowSensorData()在其中评论函数UpdateSensorProtocol()工作正常.但否则它会挂起并且GUI冻结.有什么建议!

此外,由于主线程抓取单例的运行实例,它是否真的是多线程,因为我们实际上是在单例本身中更改mUpdate,尽管是从操作屏幕.

我很困惑.

此外,有人可以提出一个关于我现在正在做什么的替代设计.

提前致谢

Tim*_*imW 5

首先,不要让系统单身. 对不同的系统使用某种Context Encapsulation .

如果你忽略了这个建议,仍然想创建"单例"线程至少QApplication::instance();用作线程的父级并放入QThread::wait()单例析构函数,否则你的程序将在程序出口处崩溃.

if(!s_instance){
    QMutexLocker lock(&mutex);
    if(!s_instance) 
        s_instance=new SensorProtocol( QApplication::instance());
} 
Run Code Online (Sandbox Code Playgroud)

但这不会解决你的问题...
Qt是事件驱动的,所以尝试使用这个非常好的事件驱动架构并为每个系统线程创建一个eventloop.然后你可以创建生活在另一个线程中的"SystemProtocols",你可以创建定时器,在线程之间发送事件,......而不使用低级同步对象.
看看Bradley T. Hughes Treading的博客文章,没有头疼

代码没有编译,但应该给你一个好主意从哪里开始...

class GuiComponent : public QWidget {
    //...
signals: 
    void start(int); // button triggerd signal
    void stop();     // button triggerd singal 

public slots:
    // don't forget to register DataPackage at the metacompiler
    // qRegisterMetaType<DataPackage>();
    void dataFromProtocol( DataPackage ){
        // update the gui the the new data 
    }
};

class ProtocolSystem : public QObject {
     //...
    int timerId;

signals:
    void dataReady(DataPackage);

public slots:
    void stop() {
       killTimer(timerId);  
    }

    void start( int interval ) {
       timerId = startTimer();  
    }

protected:
    void timerEvent(QTimerEvent * event) {
       //code to read from port when data becomes available
       // and process it and store in dataPackage
       emit dataReady(dataPackage);
    }
};

int main( int argc, char ** argv ) {

    QApplication app( argc, argv );
    // construct the system and glue them together
    ProtocolSystem protocolSystem;
    GuiComponent gui;
    gui.connect(&protocolSystem, SIGNAL(dataReady(DataPackage)), SLOT(dataFromProtocol(DataPackage)));
    protocolSystem.connect(&gui, SIGNAL(start(int)), SLOT(start(int)));
    protocolSystem.connect(&gui, SIGNAL(stop()), SLOT(stop()));
    // move communication to its thread
    QThread protocolThread;
    protocolSystem.moveToThread(&protocolThread);
    protocolThread.start(); 
    // repeat this for other systems ...
    // start the application
    gui.show();
    app.exec();
    // stop eventloop to before closing the application
    protocolThread.quit();
    protocolThread.wait();
    return 0;    
}
Run Code Online (Sandbox Code Playgroud)

现在你有完全独立的系统,gui和协议现在彼此不相同,甚至不知道程序是多线程的.您可以在单个线程环境中独立地对所有系统进行单元测试,并在实际应用程序中将它们粘合在一起,如果需要,可以在不同的线程之间进行划分.
这是我将用于此问题的程序体系结构.没有单个低级同步元素的多线程.没有竞争条件,没有锁,......