赞
踩
在软件开发中经常会碰到在一个进程内部同时处理不同业务功能的场景,这可以通过多线程的方式解决。
在开发多线程软件时,经常碰到数据访问冲突问 题,也就是不同的线程可能会同时访问同一个数据。如果不对数据进行保护,就会导致在访问数据时无法在一个CPU指令周期内完成操作,这样就会出现数据访问异常。
因此,需要对多线程访问的数据进行加锁保护。
下面举个例子说明下
使用Qt Designer 新建一个Dialog
再拖4个Push button进去,选中后点击上面按钮使其变为网关布局
保存得到ui文件, 再使用Scripts下的 pyside6-uic.exe -o 目标.py 保存的.ui 获得py的界面文件
// config.py import types class CSingleton(type): _instance = None def __call__(self, *args, **kwargs): if self._instance is None: self._instance = super.__call__(*args, **kwargs) return self._instance def singleton(cls, *args, **kwargs): instances = {} def wrapper(): if cls not in instances: instances[cls] = cls(*args, **kwargs) return instances[cls] return wrapper @singleton class CConfig: nTeacherNumber = 0 nStudentNumber = 0 def __init__(self): pass def setTeacherNumber(self, n): self.nTeacherNumber = n def getTeacherNumber(self): return self.nTeacherNumber def setStudentNumber(self, n): self.nStudentNumber = n def getStudentNumber(self): return self.nStudentNumber
// recvthread.py import sys import os from PySide6.QtCore import QMutex, QMutexLocker, QThread, QFile from config import CConfig class CRecvThread(QThread): bWorking = False bFinshed = True mtxRunning = QMutex() def __init__(self): super(CRecvThread, self).__init__() def run(self): self.bFinshed = False self.bWorking = True workspace_dir = os.path.dirname(os.path.abspath(__file__)) strFileName = workspace_dir + '/test/recv.txt' strContent = str() config = CConfig() while self.isWorking(): QThread.sleep(1) file = open(strFileName, 'r') strContent = file.read() file.close() print(strContent) strList = strContent.split(",") print(strList) if 2 == len(strList): config.setTeacherNumber(int(strList[0])) print(config.getTeacherNumber()) config.setStudentNumber(int(strList[1])) print(config.getStudentNumber()) self.bFinshed = True def isWorking(self): locker = QMutexLocker(self.mtxRunning) return self.bWorking def exitThread(self): self.mtxRunning.lock() self.bWorking = False self.mtxRunning.unlock() while not self.bFinshed: QThread.msleep(10)
// sendthread.py import os from PySide6.QtCore import QMutex, QMutexLocker, QThread, QFile from config import CConfig class CSendThread(QThread): bWorking = False bFinshed = True mtxRunning = QMutex() def __init__(self): super(CSendThread, self).__init__() def run(self): self.bFinshed = False self.bWorking = True workspace_dir = os.path.dirname(os.path.abspath(__file__)) strFileName = workspace_dir + '/test/send.txt' file = QFile(strFileName) strContent = str() config = CConfig() while self.isWorking(): QThread.sleep(1) strContent = 'teacher:{0}, student:{1}'.format(config.getTeacherNumber(), config.getStudentNumber()) if not file.open(QFile.WriteOnly|QFile.Truncate|QFile.Text): continue file.write(strContent.encode('UTF-8')) file.close() self.bFinshed = True def isWorking(self): locker = QMutexLocker(self.mtxRunning) return self.bWorking def exitThread(self): self.mtxRunning.lock() self.bWorking = False self.mtxRunning.unlock() while not self.bFinshed: QThread.msleep(10)
// cdialog.py import os import sys from PySide6.QtCore import QDir from PySide6.QtWidgets import QDialog, QApplication from recvthread import CRecvThread from sendthread import CSendThread from ui_CDialog import Ui_Dialog class cDialog(QDialog, Ui_Dialog): recvThread = CRecvThread() sendThread = CSendThread() def __init__(self, parent=None): super(cDialog, self).__init__(parent) self.setupUi(self) self.setWindowTitle('多线程') workspace_dir = os.path.dirname(os.path.abspath(__file__)) strDir = workspace_dir + '/test/' dir = QDir() if not dir.exists(strDir): dir.mkpath(strDir) self.btnStartThread.clicked.connect(self.slot_startthread) self.btnStopThread.clicked.connect(self.slot_stopthread) def __del__(self): self.slot_stopthread() def slot_startthread(self): self.recvThread.start() self.sendThread.start() def slot_stopthread(self): self.recvThread.exitThread() self.sendThread.exitThread() if __name__ == "__main__": app = QApplication(sys.argv) d = cDialog() d.exec() sys.exit(0)
点击start后
· 开发自定义线程类实现多线程开发,自定义线程类从
QThread派生。
· start()接口用来启动线程运行,需要重写线程类的 run()接口,以便实现业务功能。run()接口的主循环中应该根据工作标志判断是否需要继续执行循环。
· 编写exitThread()接口用来停止线程运行,在该接口内应该等待 run()接口退出运行。
· 使用QMutex保护数据,防止多线程访问数据时异常。可以
使用QMutexLocker简化对互斥锁的操作。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。