PySide中线程间通信的方法

15

我有一个线程,它会产生一些数据(一个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

我只会复制数据的引用(对吗?),并且在返回后,数据将被共享和解锁...这段代码正确吗? 如果数据真的很大(比如1'000'000个项目的列表),我该怎么办?

谢谢。

P.S. 我看到了一些例子,比如Qt Mandelbrot example或者threading example with PyQt,但它们在插槽中使用QImage作为参数。


顺便说一下,我认为这里有一个缺陷:这段代码可能会工作,因为slowly_produce_data()一次性返回所有数据,然后分配给一个对象变量。没有使用互斥锁,因为数据引用是一次性设置的(我认为是安全的),但如果数据在循环中生成,并按顺序构建(即不是从返回值中获取),那么也需要在那里使用互斥锁。 - AkiRoss
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)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接