2017-10-06 100 views
0

我必须通过其SDK使用Qt Gui控制摄像头的c + +。照相机由于启动问题需要花费很多时间,并且自从完成后,我的Gui仍然处于冻结状态,所以解决方案 - >线程化。我要检查相机的状态(可以同时手动控制相机),所以线程也是一个好方法。基于此tutorial。线程机制工作正确。但问题是关闭应用程序。我成为ASSERT失败(我猜想是坏内存管理)或“QThread:线程仍在运行时被销毁”有人可以帮我解决这个问题。所以让我们从头开始。这Diagram代表想要的工作流程... 令s在SDK中说,我们有以下要素硬件通信安全地线程关闭c + +和Qt

//from the <SDK_Camera_Types.h> 
enum Power 
{ 
    on = 0, 
    off = 1 
    NA =2; //not Acknowledge 
} 
struct DeviceSetting 
{ 
    public: 
    bool operational; 
    unsigned int fieldOfView; 
    unsigned int focus; 
    } 

//from the <SDK_Camera_Device.h> 
//to control the camera I use the object from the SDK 
Camera_Device myCamera 

//and to startup/stop. I use the method 
bool myCamera.SetDevicePower(Power status); 

// to find the Power status, true if no error 
bool myCamera.getDevicePower(Power &status); 

//to get the settings. I use the method, true if no error 
bool myCamera.getDeviceSettings(DeviceSettings &settings); 

,所以这是我的相机对象代码:

// Camera Class 
class SDKCamera 
{ 
SDKCamera(){}; 
~SDKCamera(){}; 

Camera_Device* myCamera = new Camera_Device(); 
DeviceSetting settings; 
Power powerStatus = NA; 
} 

之后来了主窗口:

void MyWindow::btnClicked() 
{ 
    Power powerNow = NA; 
    if (on != theCamera.powerStatus) 
     powerNow = on; 
    else powerNow = off; 
    powerControllingThread = new QThread(this); 
    powerWorker = new PowerControllingWorker(&theCamera,powerNow, &theMutex); 

    connect(powerControllingThread, SIGNAL(started()), powerWorker, SLOT(startStopCamera())); 
    connect(powerWorker, SIGNAL(done()), powerControllingThread, SLOT(quit()), Qt::DirectConnection); 
    // directConnection to emit finished() 

    connect(powerWorker, SIGNAL(done()), powerWorker, SLOT(deleteLater())); 
    connect(powerControllingThread, SIGNAL(finished()), powerControllingThread, SLOT(deleteLater())); 

    connect(powerWorker, SIGNAL(cameraOn()), this, SLOT(startRefresh())); 

    powerWorker->moveToThread(powerControllingThread); 
    powerControllingThread->start(); 
} 
void MyWindow::startRefresh() 
{ 
    settingsCheckerThread = new QThread(this); 
    settingsChecker = new SettingsCheckWorker(&theCamera,&theMutex); 

    connect(settingsCheckerThread , SIGNAL(started()), settingsChecker, SLOT(getCyclicSettings())); 
    connect(settingsChecker, SIGNAL(done()), settingsCheckerThread , SLOT(quit()), Qt::DirectConnection); 
    // directConnection to emit finished() 

    connect(settingsChecker, SIGNAL(done()), settingsChecker, SLOT(deleteLater())); 
    connect(settingsCheckerThread , SIGNAL(finished()), settingsCheckerThread , SLOT(deleteLater())); 

    connect(settingsChecker, SIGNAL(refreshed()), this, SLOT(refreshLabels())); 

    settingsChecker->moveToThread(settingsCheckerThread); 
    settingsCheckerThread->start(); 
} 

void MyWindow::closeThreads(const int time) 
{ 
    if(powerControllingThread) 
     { 
      if(!powerControllingThread->wait(time)) 
       powerControllingThread->exit(); 
     } 
    if(settingsCheckerThread) 
     { 
      if(!settingsCheckerThread->wait(time)) 
       settingsCheckerThread->exit(); 
     } 
} 

void MyWindow::Close() 
{ 
    closeThreads(1000); 
    qApp->exit(); 
} 

相机开始工人插槽如下定义:

void PowerControllingWorker::startStopCamera() 
{ 
    lock_guard<mutex> lock((*pmtx)); 
    if(true == camera->SetDevicePower(status)) 
    { 
      if(true == camera->getDevicePower(camera->powerStatus)) 
      { 
      if (on == camera->powerStatus) emit cameraOn(); 
      } 
    } 
    emit done(); 
} 

但循环工人帽子这样的定义:

void SettingsCheckWorker::getCyclicSettings() 
{ 
    while(1) 
    { 
     lock_guard<mutex> lock((*pmtx)); 
     if(on == camera->powerStatus) 
     { 
      std::this_thread::sleep_for(std::chrono::milliseconds(1000)); 
       if(true == camera->getDevicePower(camera->powerStatus)) 
       { 
        if (on == camera->powerStatus) 

        { 
         if (true ==camera->getDeviceSettings(camera->settings) 
         emit refreshed(); 
        } else break; 
       }else break; 
     }else break; 
    } 
    emit done(); 
} 

因此,如果您已经阅读直到这一行首先感谢您的耐心和这里是我的问题,如何关闭Gui并杀死线程,如果它们在运行?我也尝试过使用smart_poiters,但我还没找到正确的方式来使用它们。谢谢

+0

“所以如果你已经阅读,直到这一行..”不,我只是滚动,直到这一行,我认为你应该提供[mcve],因为这只是太多的代码 – user463035818

+1

使用QThreads而不是'std :: thread' 。它们适用于所有QT对象的生命周期。除非你完全知道你在做什么,否则不要使用“DirectConnection”。不要尝试从不由QT管理的线程调用任何QT功能。将您的QObject移动到它们应该居住的线程中。如果需要循环执行,请使用QTimers。 – Ext3h

+0

@ tobi303好的,谢谢我会尝试!但我怎样才能清楚地解释第三方图书馆? –

回答

0
if(powerControllingThread) 
{ 
    if(!powerControllingThread->wait(time)) 
     powerControllingThread->exit(); 
} 

这显然是错误的。您不能直接从其他线索致电exit()。这只能发生在相应线程的事件循环中执行的插槽内。它不完全按照你认为它会做的事情。

为了停止QThread,你必须信号QThread对象的quit()插槽和等待它关闭事件循环。

如果quit()插槽永远无法处理,因为您有类似getCyclicSettings()的问题,无限期阻止执行,那就是您的问题。插槽,即使在工作线程上,也应该尽可能快地返回。

如果您需要循环执行,请使用计时器。只有在最后一轮执行时才发出done()信号,在所有其他情况下只是在此期间离开插槽。

在你的情况下,有两个工作线程没有多少理由。 PowerControllingWorkerSettingsCheckWorker可以很容易地共存于同一个线程中。毕竟,它们无法平行运行。

最后,执行完成后立即丢弃工作线程没有意义。只要保留它直到父对象被销毁,无论如何它都会自动清理。


至于你遇到的错误:它变得更糟。

void MyWindow::closeThreads(const int time) 
{ 
    if(powerControllingThread) 
     { 
      if(!powerControllingThread->wait(time)) 
       powerControllingThread->exit(); 
     } 
    if(settingsCheckerThread) 
     { 
      if(!settingsCheckerThread->wait(time)) 
       settingsCheckerThread->exit(); 
     } 
} 

好,你尝试检查powerControllingThreadsettingsCheckerThread是否仍然存在。

除了你没有。此前,您调用了deleteLater()插槽,导致这些对象被破坏。这些指针现在悬而未决,并指向无效的记忆。

试图调用方法wait()exit()会导致内存访问冲突。

在使用Qt时,您需要使用QPointer而不是纯C指针。当对象被销毁时,这些指针自动重置为0。另一个警告这些字虽然,而不是试图保持指向另一个线程上的对象的指针。它可以在不合适的时间点删除。