Связь между потоками в PySide - PullRequest
15 голосов
/ 13 мая 2010

У меня есть поток, который производит некоторые данные (список 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

будет копировать только ссылку на данные (верно?), И данные будут переданы И разблокированы после возврата ... Этот код правильный? Что я могу сделать, если данные действительно большие (например, список из 1000 000 элементов)?

Спасибо.

P.S. Я видел несколько примеров, таких как пример Qt Mandelbrot или пример потоков с PyQt , но они используют QImage в качестве параметра в слотах.

1 Ответ

15 голосов
/ 20 ноября 2010

Я думаю, что это должно работать с 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)
...