无法使用 QMutex 锁定变量
Can't lock variable with QMutex
我是多线程方面的新手。我有一个 PySide2 应用程序。它有 3 个不同的线程。第一个是运行 GUI 的主线程,后者负责相机流,第三个负责提供 API 从其他点访问 GUI 的 Flask。 (根据文章从不同线程访问 GUI 不是一个好主意:https://realpython.com/python-pyqt-qthread/#reusing-threads-qrunnable-and-qthreadpool)。
当请求到达端点时,我想在 GUI 上获取一些值并 return 它们。我试图实现信号和槽机制来执行它。但是,在我从 GUI 获取变量之前,我的端点 returns 是变量的默认值。负责端点的线程不会等待 GUI 线程设置将被 returned 的值。我尝试以不同的方式使用 QMutex 锁定变量,首先通过 GUI 设置值,但我无法成功。如何在设置值后锁定变量和return?
在线程上运行的 Flask class:
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
共享数据class:
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(worker) 线程。我仍然想知道我是否可以使用互斥量、信号量等。
添加了暂停线程的睡眠方法。
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_())
我是多线程方面的新手。我有一个 PySide2 应用程序。它有 3 个不同的线程。第一个是运行 GUI 的主线程,后者负责相机流,第三个负责提供 API 从其他点访问 GUI 的 Flask。 (根据文章从不同线程访问 GUI 不是一个好主意:https://realpython.com/python-pyqt-qthread/#reusing-threads-qrunnable-and-qthreadpool)。
当请求到达端点时,我想在 GUI 上获取一些值并 return 它们。我试图实现信号和槽机制来执行它。但是,在我从 GUI 获取变量之前,我的端点 returns 是变量的默认值。负责端点的线程不会等待 GUI 线程设置将被 returned 的值。我尝试以不同的方式使用 QMutex 锁定变量,首先通过 GUI 设置值,但我无法成功。如何在设置值后锁定变量和return?
在线程上运行的 Flask class:
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
共享数据class:
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(worker) 线程。我仍然想知道我是否可以使用互斥量、信号量等。
添加了暂停线程的睡眠方法。
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_())