pyqt与threading结合,概率性导致程序闪退

前因

为了方便调试设备,打算用python写个界面程序,可以实时观察设备的升级过程,后面考虑允许多个设备同时OTA升级,所以打算给每个设备的升级开一个线程。

遇到的问题

给单个设备升级的时候,概率性出现以下无提示报错:

Process finished with exit code -1073741819 (0xC0000005)

排故过程

1. 代码

我一度怀疑代码有问题,但后面基本排除了,因为闪退的时候程序的运行位置是不确定的,并且有时代码可以跑好几轮.

2. 多线程共享变量

我的代码思路大概如下
全局变量存储ui指针
主线程:创建ui,并将地址存在全部变量里
子线程1:创建Http服务器,并实时监听客户端
子线程2-n:为链接的设备创建ota任务,并在界面显示实时进度

所以存在子线程需要同时操作界面,可能导致异常的发生。
因此我创建了两个简单的线程:

def function(x: int, y):
    while True:
        x += 2
        if True:
            print(threading.currentThread().name)
            win.ui.pte_serderInfo.appendPlainText(threading.currentThread().name)
        else:
            print(threading.currentThread().name + " {}".format("False"))
        sleep(0.1)
  
	value1 = 1
    t = threading.Thread(target=function, args=(value1, value1))
    t.start()

    value2 = 2
    t1 = threading.Thread(target=function, args=(value2, value2))
    t1.start()

win是界面地址,发现如果不操作界面,两个线程不会有问题。
但如果一直操作界面,那将会大概率出现0xC0000005
但我将于其中一个线程关闭,依然会出现标题所说的问题。
所以我遇到的问题并非第二种

3.兼容性

永远想不到的是我遇到的问题是兼容性问题。
其实通过度娘查询,发现有不少人说是第三方包版本兼容问题。
最后偶然把pyqt6改为pyqt5,问题一下就不见了。

后续

后面发现pyqt5的progressBar和threading也不兼容,我尝试采用以下方法规避:

1.线程通过操作全局变量,间接控制progressBar(成功)

子线程改变全局变量,主线程循环查询该变量

2.线程通过操作全局变量,通过主线程函数直接控制progressBar(失败)

将主线程的函数传出到全局变量,子线程进行操作(失败)

3.线程间通过队列传值(成功)

使用队列安全一些。
目前在主线程是使用QTimer进行接收队列。

经过上面的优化后,惊奇的发现把pyqt5改为pyqt6,也不会出现概率性闪退了。。。

自我反省

  1. 我所遇到的应该是“在子线程中操作主界面”和“第三方模块的兼容性”的问题。
  2. python虽然允许子线程操作pyqt主线程的变量或函数,但存在概率性程序崩溃的问题。
  3. 子线程想调用主线程的ui,需要间接控制,可以使用全局变量,队列等手段。
  4. 0xC0000005概率出现,大概率就是子线程直接操作了主线程的ui。

留下这篇文章主要是为了记录自己的错误,避免后面再次踩坑,再则可以提供一些思路给路过的码友们~

  • 12
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值