C++ C+中的线程问题+;
我在很多热门论坛上都问过这个问题,但没有具体的回应。我的应用程序使用串行通信与外部系统接口,每个系统都有自己的接口协议。从系统接收的数据显示在Qt 4.2.1中的GUI上 应用程序的结构如下所示:C++ C+中的线程问题+;,c++,multithreading,qt,qt4,C++,Multithreading,Qt,Qt4,我在很多热门论坛上都问过这个问题,但没有具体的回应。我的应用程序使用串行通信与外部系统接口,每个系统都有自己的接口协议。从系统接收的数据显示在Qt 4.2.1中的GUI上 应用程序的结构如下所示: 当应用程序开始时,我们有一个登录页面 有四个模块可供选择。这 实现为一个主显示 班级。四个模块中的每一个都是一个 单独的类本身。这里涉及的模块是action类,它负责收集和显示来自不同系统的数据 用户身份验证使他/她 进入动作画面。这个 动作画面的构造器 类执行并与 平凡的初始化它启动了 单独的系统线
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
};
在实现文件*.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();
}
}
运行函数的结构
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();
}
在action screen类中,我使用sigaction和saio定义了一个InputSignalHandler。这是一个函数指针,一旦数据到达任何串行端口,它就会被激活
这是一个全局函数(我们无法更改它,因为它是Linux特有的),它仅用于比较数据到达的串行端口的文件描述符和传感器系统的fd,如果在该线程上找到匹配的WaitCondition.wakeOne被调用,它将退出等待并读取和处理数据
在action screen类中,单个线程作为SensorProtocol::getInstance()->start()
启动
每个系统的协议都有一个发送数据的帧速率。基于这个事实,在actions屏幕中,我们设置了更新计时器,以协议的刷新率超时。当这些计时器超时时,将调用operation screen的UpdateSensorProtocol()函数
connect(&timer, SIGNAL(timeout), this,SLOT(UpdateSensorProtocol()));
这将获取一个传感器单例实例作为
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
}
对于singleton instance的所有使用,都使用了SensorProtocol::getInstance()
。鉴于上述情况,无论我做什么更改,我的一个协议都将挂起
如果我在UpdateSensorProtocol()
中注释ShowSensorData()
函数,则在使用UpdateSensorProtocol()显示数据时会出现挂起,它工作正常。但否则它将挂起,GUI将冻结。任何建议
另外,由于主线程获取了singleton的运行实例,它是否真的是多线程的,因为我们本质上是在改变singleton本身的mUpdate,尽管是从action screen开始的
我对此感到困惑
另外,有人能建议我现在做什么的替代设计吗
提前感谢我将首先使用RAII(资源获取即初始化)来提高锁定代码的安全性。您的代码如下所示:
mutex.lock();
...logic...
mutex.unlock();
MyMutex mutex;
...logic...
将互斥体代码包装在一个类中,在该类中互斥体在ctor中获取并在dtor中释放。现在,您的代码如下所示:
mutex.lock();
...logic...
mutex.unlock();
MyMutex mutex;
...logic...
主要的改进是,如果在逻辑部分抛出任何异常,您的互斥锁仍然会被释放
另外,不要让任何异常从线程中泄漏出来!即使您不知道如何处理它们,也可以将它们记录到某个地方。我不能完全确定问题出在哪里,因为我不知道ShowSensorData()函数(方法?)在做什么,但是您包含的代码存在一些多线程问题
mUpdate
如果被多个线程访问,则应使用互斥锁进行保护mStop
为true,则run()
方法看起来会锁定互斥锁,并且永远不会释放互斥锁您应该考虑使用实践来捕获和释放互斥体。我不知道您是否正在使用Qt互斥体,但您应该研究使用它来锁定和解锁互斥体
我会考虑改变你的代码> Syror协议< /代码>类,以使用条件变量和标志或某种事件(不确定Qt在这里提供什么)来处理与对象实例相关联的方法的内部更新。比如:
/*static*/ void
SensorProtocol::updateSensorProtocol() {
SensorProtocol *inst = SensorProtocol::getInstance();
inst->update();
}
然后确保update()
方法在读取或写入读取器和显示器之间共享的任何成员之前获取互斥体
更完整的方法是使用体系结构分离UI显示、传感器及其链接。将解决方案重构为MVC架构可能会大大简化事情。更不用说它使这样的应用程序更不容易出错。查看和类,了解如何实现这一点。据我所知,有一个关于在某处使用Qt实现MVC的教程。。。不过,我已经有好几年没有使用Qt了。看看:
QextSerialPort是一个跨平台的产品
串口类。这个班
封装两个端口上的串行端口
POSIX和Windows系统
继承并使串行端口通信与QtaPI的其余部分更平滑地集成
此外,您可以使用消息传递方案在I/O和GUI线程之间进行通信,而不是共享内存。这通常不太容易出错。您可以使用该函数将自定义QEvent消息发送到要在GUI线程中使用处理程序处理的QObject。它将为您解决同步问题,并缓解死锁问题
下面是一个简单的例子:
class IODataEvent : public QEvent
{
public:
IODataEvent() : QEvent(QEvent::User) {}
// put all of your data here
};
class IOThread : public QThread
{
public:
IOThread(QObject * parent) : QThread(parent) {}
void run()
{
for (;;) {
// do blocking I/O and protocol parsing
IODataEvent *event = new IODataEvent;
// put all of your data for the GUI into the event
qApp->postEvent(parent(), event);
// QApplication will take ownership of the event
}
}
};
class GUIObject : public QObject
{
public:
GUIObject() : QObject(), thread(new IOThread(this)) { thread->start() }
protected:
void customEvent(QEvent *event)
{
if (QEvent::User == event->type) {
IODataEvent *data = (IODataEvent *) event;
// get data and update GUI here
event->accept();
} else {
event->ignore();
}
// the event loop will release the IODataEvent memory automatically
}
private:
IOThread *thread;
};
另外,Qt 4。您的getInstance方法也可以这样编写,以避免使用s_实例变量:
SensorProtocol& getInstance()
{
static SensorProtocol instance;
return instance;
}
< >双检查锁定模式在C++中被破坏。这在互联网上都有很好的记录。我不知道您的问题是什么,但显然您需要在代码中解决此问题。问题: 使用RAII锁定
if(!s_instance){
QMutexLocker lock(&mutex);
if(!s_instance)
s_instance=new SensorProtocol( QApplication::instance());
}
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;
}