在python中处理多进程

时间:2016-07-20 09:06:47

标签: python multithreading perforce

我的代码正在处理一些并行的perforce任务,同时显示进度条并允许用户随时终止作业,问题是用户单击close按钮时线程函数未被杀死但是锁定已发布,主UI线程正在解锁。 单击p4.run_sync()按钮后,Cancel不会终止。

def P4SyncLibrary(args, que):
    syncType = args[0]
    view = args[1]
    p4 = P4CreateConnection(disable_tmp_cleanup=True)
    try:
        p4.run_sync(view)
    except P4Exception:
        for e in p4.errors:
            print "SyncError: - %s" %e
    p4.disconnect()
    que.put(None)


class CreateJob(QtGui.QDialog):
    def __init__(self, thread, args):
        QtGui.QDialog.__init__(self)
        self.ui=Ui_ProgressBar()
        self.ui.setupUi(self)
        self.ui.cancel.clicked.connect(self.closeEvent)
        self.ui.cancel.setIcon(QtGui.QIcon(QtGui.QPixmap("%s/delete.xpm" %resources)))

        self.threadControl = ThreadControl(thread=thread, args=args)
        self.connect(self.threadControl, QtCore.SIGNAL("__updateProgressBar(int)"), self.__updateProgressBar)
        self.threadControl.finished.connect(self.closeEvent)
        self.threadControl.start()

    @QtCore.pyqtSlot(int)
    def __updateProgressBar(self,val):
        self.ui.progressBar.setValue(val)
        self.setWindowTitle("Processing: {0}%".format(val))

    def closeEvent(self, QCloseEvent=None):
        if self.threadControl.isRunning():
            self.threadControl.stop()
            self.threadControl.wait()
        if QCloseEvent: QtGui.QDialog.closeEvent(self, QCloseEvent)
        else: self.close()

    def getResults(self):
        return self.threadControl.resultDict

class ThreadControl(QtCore.QThread):
    stopFlag = 0
    def __init__(self, thread=None, args=None):
        super(ThreadControl, self).__init__()
        self.args = args
        self.thread = thread
        self.resultDict = []

    def run(self):
        threads = {}
        queue = multiprocessing.Queue()
        for arg in self.args:
            process = multiprocessing.Process(target=self.thread, args=(arg, queue))
            process.start()
            threads[process] = 1 ## ACTIVE thread

        # WAIT TILL ALL PROCESSES COMPLETE
        completedThreads = 0
        total = len(threads.keys())
        while completedThreads != total:
            if self.stopFlag:
                for t in threads.keys():
                    if threads[t] == 1:
                        t.terminate()
                        t.join()
                        threads[t] = 0
                        completedThreads += 1
            else:
                for t in threads.keys():
                    if self.stopFlag: break ## Process threads termination
                    elif threads[t] == 1 and not t.is_alive():
                        threads[t] = 0
                        completedThreads += 1
                        self.resultDict.append(queue.get())
            self.emit(QtCore.SIGNAL('__updateProgressBar(int)'),(completedThreads*100)/total)
            sleep(0.5) ## Prevent CPU from overloading

    def stop(self):
        self.stopFlag=1

正在使用CreateJob

的实例创建作业
CreateJob(thread=P4SyncLibrary, args=P4Libraries).exec_()

1 个答案:

答案 0 :(得分:0)

我能给出的唯一解决方案是将p4对象作为参数传递给调用线程,以便在用户想要取消作业时p4服务器连接可以断开连接。

def P4SyncLibrary(p4, args, que):
    syncType = args[0]
    view = args[1]
    try:
        p4.run_sync(view)
    except P4Exception:
        for e in p4.errors:
            print "SyncError: - %s" %e
    que.put(None)

class ThreadControl(QtCore.QThread):

    ...

    def run(self):
        threads = {}
        queue = multiprocessing.Queue()
        for arg in self.args:
            connection = P4CreateConnection(disable_tmp_cleanup=True)
            if connection.connected():
                process = multiprocessing.Process(target=self.thread, args=(connection, arg, queue))
                process.start()
                threads[process] = {
                    'isAlive': True,
                    'connection': connection
                }

        # WAIT TILL ALL PROCESSES COMPLETE
        completedThreads = 0
        total = len(threads.keys())
        while completedThreads != total:
            if self._stop:
                for t in threads.keys():
                    if threads[t]['isAlive']:
                        threads[t]['connection'].disconnect()
                        t.terminate()
                        t.join()

                        threads[t]['isAlive'] = False
                        completedThreads += 1
            else:
                for t in threads.keys():
                    if self._stop: break ## Process threads termination
                    elif threads[t]['isAlive'] and not t.is_alive():
                        threads[t]['connection'].disconnect()
                        threads[t]['isAlive'] = False
                        completedThreads += 1
                        self.results.append(queue.get())
            self.emit(QtCore.SIGNAL('__updateProgressBar(int)'),(completedThreads*100)/total)
            sleep(0.5) ## Prevent CPU from overloading