一、问题描述
1、以下代码实现的功能是:使用串口向下面的终端发送数据,然后创建一个线程接受终端传过来的上行数据帧。
2、问题所在:在线程运行之前,串口下发数据帧的函数已经执行完毕,是可以在UI界面体现出写操作的(主线程try:中的操作)。但是实际使用中,主线程的操作总是等子线程结束后才在UI界面体现出来。我认为是主线程和子线程没有实现并发操作。
# 这里是主线程,用于通过串口下发数据
def SendDownData(self, data, printdata):
if self.ser.is_open:
try:
# 以下的操作,如self.textBrowser.append()应该在UI界面的textBrowser中打印出来
# 但事实上,总是等待子线程完成后才实现
self.ser.flushInput()#丢弃接收缓存中的所有数据,防止接受到串口的垃圾数据
self.senddata = bytes.fromhex(data) # 字符转成字节
self.ser.write(self.senddata)
ct = datetime.datetime.now()
ct_str = ct.strftime("%Y-%m-%d %H:%M:%S")
ct_str = '[ ' + ct_str + ' ]' + ': '
self.textBrowser.append('- - - - - - - - - - - - - -下行报文 - - - - - - - - - - - - - - - - ' + '\n')
self.textBrowser.append(ct_str + '下行报文已发送')
self.textBrowser.append(ct_str + '发送的报文为:')
#给字符串数据帧的每一个字节后面加一个空格
printdowndata = re.findall(".{2}", data)
printdowndata = " ".join(printdowndata)
self.textBrowser.append(printdowndata)
self.textBrowser.append(printdata)
self.textBrowser.append('- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -')
self.Create_thread()
except Exception as e:
pass
else:
QMessageBox.warning(self, '提示信息', '串口未打开!', QMessageBox.Ok,
QMessageBox.Ok)
# 创建子线程
def Create_thread(self):
self.WaitingUpDatathread = threading.Thread(target=self.ReadUpData)
self.WaitingUpDatathread.setDaemon(True)
self.WaitingUpDatathread.start()
self.WaitingUpDatathread.join()
# 子线程,使用串口接受终端响应的数据帧
def ReadUpData(self):
self.readstrdata = ''
self.timeflag = 0 #目的是让延时接受最长为3秒
while self.timeflag != 30:
self.timeflag += 1
time.sleep(0.1)
self.readbytesdata = self.ser.read_all()
self.readstrdata = self.readstrdata + self.readbytesdata.hex() # 字节转成16进制字符显示
# 接受到最短数据帧就结束循环
if len(self.readstrdata) >= 40:
break
print("上行数据帧:" + self.readstrdata)
self._Signal_GetData.emit(self.readstrdata)
左侧的下行报文的打印内容是主线程实现的,它总是在右侧子线程打印之后打印。
二、解决办法
1、解决办法就是抛弃threading库写子线程,而是使用pyqt提供的QThread库写子线程,以下是我针对我的项目的代码改写。
#创建子线程的函数
def Create_thread(self):
self.ReadUpData = ReadupdataThread(self.ser)
self.ReadUpData._Updata_Signal.connect(self.ReadUpDatasig)
self.ReadUpData.start()
def ReadUpDatasig(self, data):
self._Signal_GetData.emit(data)
# 子线程类
class ReadupdataThread(QThread):
# # pyqtSignal是信号类
_Updata_Signal = pyqtSignal(str) # 计数完成后发送一个信号
def __init__(self, ser):
super().__init__() ## 继承QThread
self.ser = ser
def run(self):
readstrdata = ''
timeflag = 0 # 目的是让延时接受最长为3秒
while timeflag != 30:
timeflag += 1
time.sleep(0.1)
readbytesdata = self.ser.read_all()
readstrdata = readstrdata + readbytesdata.hex() # 字节转成16进制字符显示
if len(readstrdata) >= 40:
break
print("上行数据帧:" + readstrdata)
self._Updata_Signal.emit(readstrdata)