PySide中线程之间的通信

15 投票
1 回答
9779 浏览
提问于 2025-04-15 22:38

我有一个线程,它会生成一些数据(一个Python列表),这些数据需要在主线程中被一个小部件读取和显示。其实,我现在是用QMutex来控制对数据的访问,方法是这样的:

class Thread(QThread):
  def get_data(self):
    QMutexLock(self.mutex)
    return deepcopy(self.data)

  def set_data(self, data):
    QMutexLock(self.mutex)
    self.data = deepcopy(data)

  def run(self):
    self.mutex = QMutex()
    while True:
      self.data = slowly_produce_data()
      self.emit(SIGNAL("dataReady()"))

class Widget(QWidget):
  def __init__(self):
    self.thread = Thread()
    self.connect(self.thread, SIGNAL("dataReady()"), self.get_data)
    self.thread.start()

  def get_data(self):
    self.data = self.thread.get_data()

  def paintEvent(self, event):
    paint_somehow(self.data)

需要注意的是,我没有在emit()中直接传递数据,因为这些数据是通用的(我尝试过用PyObject作为数据类型,但这样会导致程序崩溃,因为会出现双重free()的问题)。所以我使用deepcopy()来复制数据(假设这些数据可以这样复制)。

我使用deepcopy()是因为我觉得像下面这样的代码:

def get_data(self):
  QMutexLock(self.mutex)
  return self.data

只会复制数据的引用(对吧?),这样数据就会被共享,并且在返回后会解锁……

这个代码正确吗?如果数据真的很大(比如有100万个项目的列表),我该怎么办呢?

谢谢。

附言:我看到了一些例子,比如Qt Mandelbrot示例,或者PyQt的线程示例,但它们在槽中使用的是QImage作为参数。

1 个回答

15

我觉得这个应该可以在PySide上运行。如果不行的话,请在PySide的bugzilla网站上报告一个错误(http://bugs.openbossa.org/),并附上一个简单的测试案例:

class Thread(QThread):
  dataReady = Signal(object)

  def run(self):
    while True:
      self.data = slowly_produce_data()
      # this will add a ref to self.data and avoid the destruction 
      self.dataReady.emit(self.data) 

class Widget(QWidget):
  def __init__(self):
    self.thread = Thread()
    self.thread.dataReady.connect(self.get_data, Qt.QueuedConnection)
    self.thread.start()

  def get_data(self, data):
    self.data = data

  def paintEvent(self, event):
    paint_somehow(self.data)

撰写回答