Communication between threads in PySide

AkiRoss picture AkiRoss · May 13, 2010 · Viewed 8.8k times · Source

I have a thread which produces some data (a python list) and which shall be available for a widget that will read and display the data in the main thread. Actually, I'm using QMutex to provide access to the data, in this way:

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)

Note that I'm not passing the data in the emit() as they are generic data (I tried to use PyObject as data type, but a double free() would crash the program), but I'm copying the data with a deepcopy() (assuming the data can be copied like this). I used a deepcopy() because I guess that a code like:

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

would only copy a reference to the data (right?) and data would be shared AND unlocked after the return... Is this code correct? What can I do if data are really large (like a list of 1'000'000 items)?

Thanks.

P.S. I saw some examples, like the Qt Mandelbrot example, or the threading example with PyQt, but they use QImage as parameter in the slots.

Answer

user514461 picture user514461 · Nov 20, 2010

I think this should work with PySide. if not work please report a bug on PySide bugzilla(http://bugs.openbossa.org/) with a small test case:

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)