无法使用 QMutex 锁定变量



我是多线程的新手。我有一个PySide2应用程序。它有3个不同的线程。第一个线程是运行GUI的主线程,后者负责摄像机流,第三个线程负责提供API从其他点访问GUI的Flask。(根据这篇文章,从不同的线程访问GUI不是一个好主意:https://realpython.com/python-pyqt-qthread/#reusing-线程qrunnable和qthreadpool(。

当一个请求到达端点时,我想在GUI上获取一些值并返回它们。我试图实现信号和插槽机制来实现它。但是,在从GUI获取变量之前,我的端点会返回该变量的默认值。负责端点的线程不等待GUI线程设置将返回的值。我试着用QMutex以不同的方式锁定变量,以通过GUI设置值,但我没有成功。如何锁定变量并在设置值后返回?

在线程上运行的Flask类:

from PySide2.QtCore import Signal, QObject, Slot, QMutex
from flask import Flask
from SharedData import SharedData
class API(QObject):
signal_get_value = Signal()
def __init__(self):
super(API, self).__init__()
self.app = Flask(__name__)
self.app.add_url_rule('/get_value/', 'get_value', self.get_value)
self.data = SharedData()

def start(self):
self.app.run()
def get_value(self):
self.signal_get_value.emit()
measurement = self.data.get_measurement()
data = {"measurement": measurement}
return data

SharedData类:

class SharedData:
__measurement = None
@classmethod
def get_measurement(cls):
return cls.__measurement
@classmethod
def set_measurement(cls, measurement):
cls.__measurement = measurement

在我的GUI模块中更改值的方法:

mutex = QMutex()
def read_measurement(self):
self.mutex.lock()

#some processes and the output assign to the 'result' variable

self.api.data.set_measurement(result)
self.mutex.unlock()

编辑

我添加了一个代码来澄清它。你可以在其中找到read_measurement方法。其余代码相同@eyllanesc

import sys
from PySide2.QtCore import QThread, QMutex
from PySide2.QtGui import QPixmap
from PySide2.QtWidgets import QApplication, QVBoxLayout, QWidget, QPushButton, QHBoxLayout, QLabel
from API import API
class MainWindow(QWidget):
def __init__(self):
super(MainWindow, self).__init__()
self.init_UI()

def init_UI(self):
self.setFixedSize(690, 530)
self.image_lbl = QLabel()
self.image_lbl.setPixmap(QPixmap("img/im.jpg"))
btn_cnt = QPushButton("Continue")
btn_pa = QPushButton("Pause")
hbox = QHBoxLayout()
hbox.addWidget(btn_cnt)
hbox.addWidget(btn_pa)
vbox = QVBoxLayout()
vbox.addWidget(self.image_lbl)
vbox.addLayout(hbox)
self.setLayout(vbox)
self.start_api()
self.show()

def start_api(self):
self.thread_API = QThread()
self.api = API()
self.api.moveToThread(self.thread_API)
self.thread_API.started.connect(self.api.start)
self.api.signal_get_value.connect(self.read_measurement)
self.thread_API.start()
dv = 0
mutex = QMutex()
def read_measurement(self):
self.mutex.lock()
measurement = None
result = "measurement " + str(self.dv)
self.dv += 1
self.api.data.set_measurement(result)
self.mutex.unlock()

if __name__ == '__main__':
app = QApplication(sys.argv)
main_form = MainWindow()
sys.exit(app.exec_())

解决问题的方法是暂停API(工作线程(。我仍然想知道我可以使用互斥、信号量等吗

添加了睡眠方法来暂停线程。

from time import sleep
from PySide2.QtCore import Signal, QObject, Slot, QMutex
from flask import Flask
from SharedData import SharedData
class API(QObject):
signal_get_value = Signal()
def __init__(self):
super(API, self).__init__()
self.__app = Flask(__name__)
self.__app.add_url_rule('/get_value/', 'get_value', self.get_value)
self.data = SharedData()
self.pause = True

def start(self):
self.__app.run()
def __sleep_thread(self):
"""method pauses the thread to enable other threads to get the request done 
Returns
-------
None
"""
while self.pause:
sleep(0.05)
self.pause = True

def get_value(self):
self.signal_get_value.emit()
self.__sleep_thread()
measurement = self.data.get_measurement()
data = {"measurement": measurement}
return data

GUI模块。

import sys
from PySide2.QtCore import QThread, QMutex
from PySide2.QtGui import QPixmap
from PySide2.QtWidgets import QApplication, QVBoxLayout, QWidget, QPushButton, QHBoxLayout, QLabel
from API import API
class MainWindow(QWidget):
def __init__(self):
super(MainWindow, self).__init__()
self.init_UI()

def init_UI(self):
self.setFixedSize(690, 530)
self.image_lbl = QLabel()
self.image_lbl.setPixmap(QPixmap("img/im.jpg"))
btn_cnt = QPushButton("Continue")
btn_pa = QPushButton("Pause")
hbox = QHBoxLayout()
hbox.addWidget(btn_cnt)
hbox.addWidget(btn_pa)
vbox = QVBoxLayout()
vbox.addWidget(self.image_lbl)
vbox.addLayout(hbox)
self.setLayout(vbox)
self.start_api()
self.show()

def start_api(self):
self.thread_API = QThread()
self.api = API()
self.api.moveToThread(self.thread_API)
self.thread_API.started.connect(self.api.start)
self.api.signal_get_value.connect(self.read_measurement)
self.thread_API.start()
# ToDo: Do I need the terminate thread when exited from the app?
dv = 0
def read_measurement(self):
measurement = None
result = "measurement " + str(self.dv)
self.dv += 1
self.api.data.set_measurement(result)
self.api.pause = False

if __name__ == '__main__':
app = QApplication(sys.argv)
main_form = MainWindow()
sys.exit(app.exec_())

最新更新