PyQT5:更新QTreeView后出现访问冲突((0xC0000005)错误

时间:2019-06-12 17:45:41

标签: model-view-controller pyqt5 python-3.6

当我尝试通过dataChanged信号更新QTreeView时,出现访问冲突错误(进程以退出代码-1073741819(0xC0000005)完成)。

我在Windows 10 x64上使用Python 3.6,Pyqt5。

更新程序线程

class Queue_Updater(QThread):
    clientSignal = pyqtSignal(dict)
    processSignal = pyqtSignal(dict)
    torrentSignal = pyqtSignal(dict)
    distributedSignal = pyqtSignal(dict)

    def __init__(self, queue=None, parent=None):
        QThread.__init__(self, parent)
        self.q = queue
        self.threadactive=True

    def run(self):
        try:
            while self.threadactive:
                time.sleep(1)
                for cmd in iter(self.q.get, None):
                    for cmd_id, data in cmd.items():
                        if (cmd_id == commands.peers) or (cmd_id == commands.leechers):
                            self.clientSignal.emit(data)
                        elif cmd_id == commands.processes:
                            self.processes = data[0]
                            self.clientSignal.emit(data[1])
                            self.processSignal.emit(data[0])
                        elif cmd_id == commands.list_of_torrents:
                            self.torrents = data
                            self.torrentSignal.emit(data)
                        elif cmd_id == events.successfully_distributed or events.unsuccessfully_distributed:
                            self.distributedSignal.emit(data)
        except Exception:
            print("Queue_Updater ")

    def stop(self):
        self.threadactive=False
        self.wait()

QtShell-主应用程序

class QtShell(QMainWindow):
    recheck_clients_by_list_sig = pyqtSignal()

    def __init__(self, args):
        ...
        self.ClientsView, self.ClPrModel = make_clientView(self, self.client_from_tasks, self.condition, self.mutex)
        self.TaskView, self.TaskModel = make_taskview(self, str(self._outcome), self.condition, self.mutex)

        self.updater = Queue_Updater(queue=self.queue_out, parent=self)

        self.updater.processSignal.connect(self.update_proc_data)
        self.updater.clientSignal.connect(self.TaskModel.upd_clients_data_intasks_slot)
        self.updater.torrentSignal.connect(self.update_tasks_slot)
        self.updater.distributedSignal.connect(self.TaskModel.upd_complexees_proc_status)

        self.updater.start(QThread.LowPriority)
        self.server = spawner(args, target=tracker_server,  name='TrackerServer')
        self.server.start()

    ...

    @pyqtSlot(dict)
    def update_proc_data(self, data):
        if self.mutex.tryLock():
            LeftUpperIndex, RightDownerIndex = self.ClPrModel.update_process(data)
            #Here i'm trying to update view by direct call 'dataChanged'
            #method. But effect with a send self.dataChanged() signal is a same.   
            self.ClientsView.dataChanged(QModelIndex(), QModelIndex())
            self.mutex.unlock()

    @pyqtSlot(dict)
    def update_clients_data(self, data):
        if self.mutex.tryLock():
            LeftUpperIndex, RightDownerIndex = self.ClPrModel.update_clients(data)
            self.ClientsView.dataChanged(QModelIndex(), QModelIndex())
            self.mutex.unlock()

    @pyqtSlot()
    def update_tasks_slot(self):
        if self.mutex:
            if self.mutex.tryLock():
                tasks = self.get_tasks_from_outcome(fpath=self._outcome)
                self.TaskModel.task_update(tasks)
                self._check_tasks_status(tasks)
                self.mutex.unlock()


    def get_tasks_from_outcome(self, fpath=None):
        result = None
        if fpath:
            if not fpath == self._outcome:
                address = "\\".join(fpath.split("\\")[:-1])
            else:
                address = self._outcome
            if os.path.exists(address):
                task_list = [f for f in os.listdir(address) if f.endswith(".task")]
                config = configparser.ConfigParser()
                for t in task_list:
                    config.read(os.path.join(address, t))
                    sections = config.sections()
                    if "MAIN" in sections:
                        if not result:
                            result = {}
                        result[t] = {}
                        for o in config.options("MAIN"):
                            result[t][o] = config["MAIN"][o]
            else:
                print("get_tasks_from_outcome: fpath doesn't exist")
        return result

更新方法

def update_process(self, process):
    LeftUpperIndex = None
    RightDownerIndex = None
    if isinstance(process, dict):
        for uuid, proc in process.items():
            id = self.root_item.get_child_id(uuid)
            if id >= 0:
                client = self.root_item.child(id)
                if not LeftUpperIndex:
                    LeftUpperIndex = client.index()
                list_for_remove = client.cut_through_the_list(proc)
                for p in list_for_remove:
                    self.__remove_rows(p.row(), 1, client)
                for num, data in proc.items():
                    is_in, proc_num = client.has_process(data[PROC_NAME])
                    if is_in:
                        process = client.child(proc_num)
                        process.setData(NUM, '{})'.format(proc_num))
                        process.setData(PROC_NAME, '{}: {}'.format(PROC_NAME, data[PROC_NAME]))
                        process.setData(PROC_STS, '{}: {}'.format(PROC_STS, data[PROC_STS]))
                        process.setData(PROC_PRGR, '{}: {}%'.format(PROC_PRGR, data[PROC_PRGR]))
                    else:
                        if not 'TrackerLoop' in data[PROC_NAME]:
                            item = ProcItem({NUM: '{})'.format(num),
                                             EMPTY: "",
                                             PROC_NAME: '{}: {}'.format(PROC_NAME, data[PROC_NAME]),
                                             PROC_STS: '{}: {}'.format(PROC_STS, data[PROC_STS]),
                                             PROC_PRGR: '{}: {}%'.format(PROC_PRGR, data[PROC_PRGR])},
                                            parent=client)
                            client.appendChild(item)
                if not RightDownerIndex and len(client.all_childs()) > 0:
                    last_child = client.child(-1)
                    RightDownerIndex = last_child.index()
    return LeftUpperIndex, RightDownerIndex

def update_clients(self, client):
        if isinstance(client, dict):
                    LeftUpperIndex = None
                    RightDownerIndex = None
                    if len(client) >= self.root_item.childCount():
                        for uuid, data in client.items():
                            id = self.root_item.get_child_id(uuid)
                            if id < 0:
                                item = ClientItem({CHECKED: "",
                                                    ID:uuid,
                                                    NAME:data['name'],
                                                    ADDRESS:data['addr'][0],
                                                    PORT:data['addr'][1],
                                                    DISTRIBUTOR:data[DISTRIBUTOR]},
                                                    parent=self.root_item)
                                self.root_item.appendChild(item)
                                RightDownerIndex = self.index(self.root_item.child(-1).row(),
                                                              0,
                                                              QModelIndex())
                    else:
                        remain = [uuid for uuid, data in client.items()]
                        excess = [c for c in self.root_item.childItems if c.id not in remain]
                        for client in excess:
                            self.__remove_rows(client.row(), 1, self.root_item)
                    leftUp, rightDown = self.recheck_clients_by_list_slot()
                    if RightDownerIndex:
                        LeftUpperIndex = self.index(0, 0, QModelIndex())
                    return LeftUpperIndex, RightDownerIndex
        return QModelIndex(), QModelIndex()


  def __remove_rows(self, position, rows, parent):
        success = True
        parentIndex = parent.index()
        for i in range(position, position+rows):
            self.beginRemoveRows(parentIndex, i, i)
            success = success & parent.removeChild(parent.child(i))
            self.endRemoveRows()
        return success

我有一个QTreeView,它通过另一个线程的信号更新它自己的数据。在数据量增加之前,一切都很好。

当信号中的数据被迫从模型中删除一些数据时,问题就开始了。 再次:当我将数据添加到TreeModel(QAbstractItemModel)时,一切都很好。 当我从TreeModel(QAbstractItemModel)删除数据时,此后或一段时间后,但GUI进程崩溃并显示错误:

以退出代码-1073741819(0xC0000005)完成的过程

我尝试使用QMutex和multiprocessing.conditions。这是尝试将更新和删除TreeModel(QAbstractModel)中的数据的过程相互隔离。

它实际上是没有用的,因为据我所知,pyqtSignal / Slot架构师从一开始就是线程安全的。

我也尝试遵循这篇文章的建议: Qt QAbstractItemModel - item removal crashes 它建议使用'beginRemoveRows'和'endRemoveRows'删除数据,但这没有帮助。

0 个答案:

没有答案