【问题标题】:QThread weird behaviour [closed]QThread奇怪的行为[关闭]
【发布时间】:2013-12-27 21:42:03
【问题描述】:

我有一个 QThread 运行一些代码,我希望它能够很好地退出并进行一些清理,所以代码如下:

testdevice.h

class testDevice : public QThread 
{
    Q_OBJECT
... // some definitions 

protected:
    void run(void);

private:
    hid_device *handle;
    bool abort;

public:
    ~testDevice(void);
};

testdevice.cpp

testDevice::~testDevice(void)
{    
    mutex.lock();
    abort = true;
    mutex.unlock();
    wait();

    if (handle != NULL)
    {
        hid_close(handle);
    }

    hid_exit();
}

void testDevice::run(void)
{    
    while(true)
    {        
        mutex.lock();
        if(abort)
        {
           return;
        }
       mutex.unlock();
       if (_connected)
       {
        //... more code
       }
       else // Case device is not connected
       { 
       emit deviceConnected(_connected);// A breakpoint in here is not triggered after abort is true
       handle = hid_open(TEST_VID, TEST_PID, NULL); // this is where VS2010 shows the error "Unhandled exception at 0x71241a95 in project.exe: 0xC0000005: Access violation."
       //...code continues

我期望的行为是调用run(),当调用~testDevice()析构函数时abort设置为truewait阻塞析构函数,runreturns然后析构函数继续.

发生的事情是 run() 被调用,当我关闭应用程序时,析构函数 ~testDevice() 被调用,abort 设置为 truewait() 返回并且析构函数完成......但是然后run() 继续运行,我在 project.exe 中的 0x71241a95 处得到未处理的异常:0xC0000005:访问冲突.....我将其作为 VS2010 调试运行,如果我放置断点,我会一直得到这个,但没有断点我只是偶尔得到这个……有什么线索吗?

奇怪的是,当我在abort = true; 中放置一个断点时,有时第一个断点会出现一个蓝色的小“!”标志,第二次击中是普通的全红。 emit deviceConnected(_connected); 的断点也会发生同样的情况,但这也有点随机......我不知道这是什么“!”意味着...所有这些都可能是调试问题吗?

我的普遍怀疑是 HIDAPI 在单独的线程中运行,并且当有人调用 hid_exit(); 时,它有自己的错误,也许 hid_read(); 继续运行并且由于调用了 hid_quit();hid_read(); 丢失了一些指针并且没有关闭...只是一个狂野的镜头,为了确认这一点,我需要 HIDAPI 的一些开发人员前来并说点什么...我希望他们能阅读这篇文章

【问题讨论】:

  • 阅读有关线程安全、同步(和原子)的信息 - 您正在阅读和修改 abort 并使用两个没有同步的不同线程 => 未定义的行为。
  • 我过去写了一个很好的答案:stackoverflow.com/questions/19388207/how-to-stop-thread-qthread/… 基本上,您使用volatile bool 而不是bool,编译器不会过度优化您的逻辑。或者您可以查看 Qt 附带的一些不错的线程同步功能。希望对您有所帮助。
  • @LaszloPapp:无论是分配一个常量值还是大象都与它无关。数据竞争的定义(在 C++11 和 C11 中)是(简化的)“两个线程访问同一个(非原子)对象,并且其中至少一个执行写入”。这里不能保证在一个线程中写入abort 对另一个线程是可见的,这是未定义的行为。
  • @LaszloPapp:根据我对问题的理解,OP 在关闭应用程序时正在调用一个特定 QThread 的析构函数。该特定析构函数将(可能)从主线程运行,并尝试对运行该特定 QThread 的run() 方法但设置abort 的线程产生影响。那是“非法的”。如果没有共享数据,显然不存在线程安全问题。
  • @Mat: 但他在设置中止后等待线程退出。那么同步有什么问题呢? OP似乎已经做到了。请注意,abort 成员数据是特定于线程的,因此不同线程(QThread 实例)之间没有共享。

标签: c++ multithreading qt qthread qtcore


【解决方案1】:

您似乎以自定义方式使用QThread,而不是通常的start()quit() 执行。如果您可以使用quit() 重构代码以退出QThread,那么理想情况下最好的情况是,因为这将更接近此QObject 子类的信号/槽机制。

但是,我同意这并不总是可行的。根据您提供的几行代码,我还不能告诉您这在这种特殊情况下是有意义的,但至少我会鼓励您考虑一下。

此外,您可以使用QWaitCondition 来等待某事发生,而不是使用低级或/和自定义wait() 调用。

至于快速解决您面临的问题,如果手头的问题是编译器优化布尔值(例如将其放入缓存),您可以尝试使用 std::atomic(C++11 ) 或QAtomicInt 选项。这将确保编译器无法优化读取和写入。

你会用 std typedef 写这样的东西:

std::atomic_bool abort;

如果您需要支持 C++-11 之前的编译器以及 Qt 4,您可以像这样使用 Qt 类:

QAtomicInt abort;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-11-03
    • 1970-01-01
    • 2016-02-16
    • 2017-01-02
    • 1970-01-01
    • 2017-01-09
    • 1970-01-01
    相关资源
    最近更新 更多