class PMGThreadWorker(QObject): """ 利用mutex加锁 """ signal_print = Signal(str) def __init__(self, worker_id: int): super(PMGThreadWorker, self).__init__() self.quit = False self.id = worker_id self.mutex = QMutex() self.wait_condition = QWaitCondition() def work(self): i = 0 while (1): self.mutex.lock() print(self.thread()) self.wait_condition.wait(self.mutex) for i in range(3): self.signal_print.emit(str(self.id) + ',' + str(i + 1)) i += 1 if self.quit: break self.mutex.unlock() def on_exit(self): self.quit = True self.wait_condition.wakeAll() def wake_all(self): self.wait_condition.wakeAll()
class ConsoleInitThread(QObject): initialized = Signal(object, object) def __init__(self, *args, **kwargs): super(ConsoleInitThread, self).__init__(*args, **kwargs) self.mutex = QMutex() self.wait_condition = QWaitCondition() def run(self): self.mutex.lock() kernel_manager = QtKernelManager(kernel_name='python3') kernel_manager.start_kernel() kernel_client = kernel_manager.client() kernel_client.start_channels() # notify to update ui self.initialized.emit(kernel_manager, kernel_client) # wait for exit self.wait_condition.wait(self.mutex) self.mutex.unlock() # stop channels and kernel kernel_client.stop_channels() kernel_manager.shutdown_kernel( now=True) # add now=True; Fix exit error; 200924 liugang def stop(self): self.wait_condition.wakeAll()
class BaseThread(QThread, metaclass=QABCMeta): """Base thread of Cython functions.""" @abstractmethod def __init__(self, parent: QWidget) -> None: super(BaseThread, self).__init__(parent) self.finished.connect(self.deleteLater) self.is_stop = False self.mutex = QMutex() @Slot() def stop(self) -> None: """Stop the algorithm.""" self.mutex.unlock() self.is_stop = True self.mutex.lock()
def work(p): global i, j j += 1 mutex = QMutex() print('start') while (1): mutex.lock() # print(self.thread()) # self.wait_condition.wait(self.mutex) # for j in range(3): # print(j) i += 1 p.signal_print.emit(repr(('thread:%d' % p.id, i))) # print('thread:%d' % p.id, i, '\n') p.thread().msleep(10) # mutex.unlock() if i > 100: break
class ZoomEventBuffer(object): """ A mutex-lockable buffer that stores zoom request events. """ def __init__(self): self.buffer = [] self.mutex = QMutex() def _clear(self): self.mutex.lock() self.buffer = [] self.mutex.unlock() def _put(self, value): self.mutex.lock() # Don't let the buffer fill up too much. # Keep just the most recent zoom events. while len(self.buffer) > 5: self.buffer.pop() self.buffer.insert(0, value) self.mutex.unlock() def _get(self): self.mutex.lock() if len(self.buffer) > 0: value = self.buffer.pop() else: value = None self.mutex.unlock() return value
class UpdateThread(QThread): pixmapReady = Signal(QImage) stopped = Signal() errored = Signal(str) def __init__(self, cam_id, image_width, image_height): super(UpdateThread, self).__init__() self._width = 640 self._height = 480 self._stopped = False self._update_mutex = QMutex() self._cam_id = cam_id self._image_width = image_width self._image_height = image_height @property def width(self): return self._width @width.setter def width(self, value): self._update_mutex.lock() self._width = value self._update_mutex.unlock() @property def height(self): return self._height @height.setter def height(self, value): self._update_mutex.lock() self._height = value self._update_mutex.unlock() def stop(self): self._update_mutex.lock() self._stopped = True self._update_mutex.unlock() def run(self): try: import cv2 except ImportError as e: self.errored.emit(str(e)) self.stopped.emit() return try: ueye = UEye(self._cam_id, self._image_width, self._image_height) except CameraException as e: self.errored.emit(str(e)) self.stopped.emit() return self._ueye.start_video_capture() while True: try: self._update_mutex.lock() if self._stopped: ueye.close() del ueye self.stopped.emit() return finally: self._update_mutex.unlock() frame = ueye.get_video_frame() if frame is None: ueye.close() del ueye self.stopped.emit() return rgb_image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) h, w, ch = rgb_image.shape bytes_per_line = ch * w convert_to_qt_format = QImage( rgb_image.data, w, h, bytes_per_line, QImage.Format_RGB888 ) try: self._update_mutex.lock() p = convert_to_qt_format.scaled( self._width, self._height, Qt.KeepAspectRatio ) finally: self._update_mutex.unlock() self.pixmapReady.emit(p)
class ExternalShellBase(QWidget): """External Shell widget: execute Python script in a separate process""" SHELL_CLASS = None redirect_stdio = Signal(bool) sig_finished = Signal() def __init__(self, parent=None, fname=None, wdir=None, history_filename=None, show_icontext=True, light_background=True, menu_actions=None, show_buttons_inside=True, show_elapsed_time=True): QWidget.__init__(self, parent) self.menu_actions = menu_actions self.write_lock = QMutex() self.buffer_lock = QMutex() self.buffer = [] self.run_button = None self.kill_button = None self.options_button = None self.icontext_action = None self.show_elapsed_time = show_elapsed_time self.fname = fname if wdir is None: wdir = osp.dirname(osp.abspath(fname)) self.wdir = wdir if osp.isdir(wdir) else None self.arguments = "" self.shell = self.SHELL_CLASS(parent, get_conf_path(history_filename)) self.shell.set_light_background(light_background) self.shell.execute.connect(self.send_to_process) self.shell.sig_keyboard_interrupt.connect(self.keyboard_interrupt) # Redirecting some SIGNALs: self.shell.redirect_stdio.connect( lambda state: self.redirect_stdio.emit(state)) self.state_label = None self.time_label = None vlayout = QVBoxLayout() toolbar_buttons = self.get_toolbar_buttons() if show_buttons_inside: self.state_label = QLabel() hlayout = QHBoxLayout() hlayout.addWidget(self.state_label) hlayout.addStretch(0) hlayout.addWidget(self.create_time_label()) hlayout.addStretch(0) for button in toolbar_buttons: hlayout.addWidget(button) vlayout.addLayout(hlayout) else: vlayout.setContentsMargins(0, 0, 0, 0) vlayout.addWidget(self.get_shell_widget()) self.setLayout(vlayout) self.resize(640, 480) if parent is None: self.setWindowIcon(self.get_icon()) self.setWindowTitle(_("Console")) self.t0 = None self.timer = QTimer(self) self.process = None self.is_closing = False if show_buttons_inside: self.update_time_label_visibility() @Slot(bool) def set_elapsed_time_visible(self, state): self.show_elapsed_time = state if self.time_label is not None: self.time_label.setVisible(state) def create_time_label(self): """Create elapsed time label widget (if necessary) and return it""" if self.time_label is None: self.time_label = QLabel() return self.time_label def update_time_label_visibility(self): self.time_label.setVisible(self.show_elapsed_time) def is_running(self): if self.process is not None: return self.process.state() == QProcess.Running def get_toolbar_buttons(self): if self.run_button is None: self.run_button = create_toolbutton( self, text=_("Run"), icon=ima.icon('run'), tip=_("Run again this program"), triggered=self.start_shell) if self.kill_button is None: self.kill_button = create_toolbutton( self, text=_("Kill"), icon=ima.icon('kill'), tip=_("Kills the current process, " "causing it to exit immediately")) buttons = [self.run_button] if self.options_button is None: options = self.get_options_menu() if options: self.options_button = create_toolbutton( self, text=_('Options'), icon=ima.icon('tooloptions')) self.options_button.setPopupMode(QToolButton.InstantPopup) menu = QMenu(self) add_actions(menu, options) self.options_button.setMenu(menu) if self.options_button is not None: buttons.append(self.options_button) buttons.append(self.kill_button) return buttons def set_icontext_visible(self, state): """Set icon text visibility""" for widget in self.get_toolbar_buttons(): if state: widget.setToolButtonStyle(Qt.ToolButtonTextBesideIcon) else: widget.setToolButtonStyle(Qt.ToolButtonIconOnly) def get_options_menu(self): self.show_time_action = create_action( self, _("Show elapsed time"), toggled=self.set_elapsed_time_visible) self.show_time_action.setChecked(self.show_elapsed_time) actions = [self.show_time_action] if self.menu_actions is not None: actions += [None] + self.menu_actions return actions def get_shell_widget(self): return self.shell def get_icon(self): raise NotImplementedError def show_time(self, end=False): if self.time_label is None: return elapsed_time = time() - self.t0 if elapsed_time > 24 * 3600: # More than a day...! format = "%d %H:%M:%S" else: format = "%H:%M:%S" if end: color = "#AAAAAA" else: color = "#AA6655" text = "<span style=\'color: %s\'><b>%s" \ "</b></span>" % (color, strftime(format, gmtime(elapsed_time))) self.time_label.setText(text) def closeEvent(self, event): if self.process is not None: self.is_closing = True self.process.kill() self.process.waitForFinished(100) try: self.timer.timeout.disconnect(self.show_time) except (RuntimeError, TypeError): pass def set_running_state(self, state=True): self.set_buttons_runnning_state(state) self.shell.setReadOnly(not state) if state: if self.state_label is not None: self.state_label.setText( _("<span style=\'color: #44AA44\'><b>Running...</b></span>" )) self.t0 = time() self.timer.timeout.connect(self.show_time) self.timer.start(1000) else: if self.state_label is not None: self.state_label.setText(_('Terminated.')) try: self.timer.timeout.disconnect(self.show_time) except (RuntimeError, TypeError): pass def set_buttons_runnning_state(self, state): self.run_button.setVisible(not state) self.kill_button.setVisible(state) @Slot(bool) def start_shell(self, ask_for_arguments=False): """Start shell""" if ask_for_arguments and not self.get_arguments(): self.set_running_state(False) return try: self.terminate_button.clicked.disconnect(self.process.terminate) self.kill_button.clicked.disconnect(self.process.terminate) except (AttributeError, RuntimeError, TypeError): pass self.create_process() @Slot() def get_arguments(self): arguments, valid = QInputDialog.getText(self, _('Arguments'), _('Command line arguments:'), QLineEdit.Normal, self.arguments) if valid: self.arguments = to_text_string(arguments) return valid def create_process(self): raise NotImplementedError def finished(self, exit_code, exit_status): self.shell.flush() self.sig_finished.emit() if self.is_closing: return self.set_running_state(False) self.show_time(end=True) #=============================================================================== # Input/Output #=============================================================================== def transcode(self, qba): try: return to_text_string(qba.data(), 'utf8') except UnicodeDecodeError: return qba.data() def get_stdout(self): self.process.setReadChannel(QProcess.StandardOutput) qba = QByteArray() while self.process.bytesAvailable(): qba += self.process.readAllStandardOutput() return self.transcode(qba) def get_stderr(self): self.process.setReadChannel(QProcess.StandardError) qba = QByteArray() while self.process.bytesAvailable(): qba += self.process.readAllStandardError() return self.transcode(qba) def write_output(self): # if we are already writing something else, # store the present message in a buffer if not self.write_lock.tryLock(): self.buffer_lock.lock() self.buffer.append(self.get_stdout()) self.buffer_lock.unlock() if not self.write_lock.tryLock(): return self.shell.write(self.get_stdout(), flush=True) while True: self.buffer_lock.lock() messages = self.buffer self.buffer = [] if not messages: self.write_lock.unlock() self.buffer_lock.unlock() return self.buffer_lock.unlock() self.shell.write("\n".join(messages), flush=True) def send_to_process(self, qstr): raise NotImplementedError def send_ctrl_to_process(self, letter): char = chr("abcdefghijklmnopqrstuvwxyz".index(letter) + 1) byte_array = QByteArray() byte_array.append(char) self.process.write(byte_array) self.process.waitForBytesWritten(-1) self.shell.write(LOCALE_CODEC.toUnicode(byte_array), flush=True) def keyboard_interrupt(self): raise NotImplementedError
class ExternalShellBase(QWidget): """External Shell widget: execute Python script in a separate process""" SHELL_CLASS = None redirect_stdio = Signal(bool) sig_finished = Signal() def __init__(self, parent=None, fname=None, wdir=None, history_filename=None, show_icontext=True, light_background=True, menu_actions=None, show_buttons_inside=True, show_elapsed_time=True): QWidget.__init__(self, parent) self.menu_actions = menu_actions self.write_lock = QMutex() self.buffer_lock = QMutex() self.buffer = [] self.run_button = None self.kill_button = None self.options_button = None self.icontext_action = None self.show_elapsed_time = show_elapsed_time self.fname = fname if wdir is None: wdir = osp.dirname(osp.abspath(fname)) self.wdir = wdir if osp.isdir(wdir) else None self.arguments = "" self.shell = self.SHELL_CLASS(parent, get_conf_path(history_filename)) self.shell.set_light_background(light_background) self.shell.execute.connect(self.send_to_process) self.shell.sig_keyboard_interrupt.connect(self.keyboard_interrupt) # Redirecting some SIGNALs: self.shell.redirect_stdio.connect( lambda state: self.redirect_stdio.emit(state)) self.state_label = None self.time_label = None vlayout = QVBoxLayout() toolbar_buttons = self.get_toolbar_buttons() if show_buttons_inside: self.state_label = QLabel() hlayout = QHBoxLayout() hlayout.addWidget(self.state_label) hlayout.addStretch(0) hlayout.addWidget(self.create_time_label()) hlayout.addStretch(0) for button in toolbar_buttons: hlayout.addWidget(button) vlayout.addLayout(hlayout) else: vlayout.setContentsMargins(0, 0, 0, 0) vlayout.addWidget(self.get_shell_widget()) self.setLayout(vlayout) self.resize(640, 480) if parent is None: self.setWindowIcon(self.get_icon()) self.setWindowTitle(_("Console")) self.t0 = None self.timer = QTimer(self) self.process = None self.is_closing = False if show_buttons_inside: self.update_time_label_visibility() @Slot(bool) def set_elapsed_time_visible(self, state): self.show_elapsed_time = state if self.time_label is not None: self.time_label.setVisible(state) def create_time_label(self): """Create elapsed time label widget (if necessary) and return it""" if self.time_label is None: self.time_label = QLabel() return self.time_label def update_time_label_visibility(self): self.time_label.setVisible(self.show_elapsed_time) def is_running(self): if self.process is not None: return self.process.state() == QProcess.Running def get_toolbar_buttons(self): if self.run_button is None: self.run_button = create_toolbutton(self, text=_("Run"), icon=ima.icon('run'), tip=_("Run again this program"), triggered=self.start_shell) if self.kill_button is None: self.kill_button = create_toolbutton(self, text=_("Kill"), icon=ima.icon('kill'), tip=_("Kills the current process, " "causing it to exit immediately")) buttons = [self.run_button] if self.options_button is None: options = self.get_options_menu() if options: self.options_button = create_toolbutton(self, text=_('Options'), icon=ima.icon('tooloptions')) self.options_button.setPopupMode(QToolButton.InstantPopup) menu = QMenu(self) add_actions(menu, options) self.options_button.setMenu(menu) if self.options_button is not None: buttons.append(self.options_button) buttons.append(self.kill_button) return buttons def set_icontext_visible(self, state): """Set icon text visibility""" for widget in self.get_toolbar_buttons(): if state: widget.setToolButtonStyle(Qt.ToolButtonTextBesideIcon) else: widget.setToolButtonStyle(Qt.ToolButtonIconOnly) def get_options_menu(self): self.show_time_action = create_action(self, _("Show elapsed time"), toggled=self.set_elapsed_time_visible) self.show_time_action.setChecked(self.show_elapsed_time) actions = [self.show_time_action] if self.menu_actions is not None: actions += [None]+self.menu_actions return actions def get_shell_widget(self): return self.shell def get_icon(self): raise NotImplementedError def show_time(self, end=False): if self.time_label is None: return elapsed_time = time()-self.t0 if elapsed_time > 24*3600: # More than a day...! format = "%d %H:%M:%S" else: format = "%H:%M:%S" if end: color = "#AAAAAA" else: color = "#AA6655" text = "<span style=\'color: %s\'><b>%s" \ "</b></span>" % (color, strftime(format, gmtime(elapsed_time))) self.time_label.setText(text) def closeEvent(self, event): if self.process is not None: self.is_closing = True self.process.kill() self.process.waitForFinished(100) try: self.timer.timeout.disconnect(self.show_time) except (RuntimeError, TypeError): pass def set_running_state(self, state=True): self.set_buttons_runnning_state(state) self.shell.setReadOnly(not state) if state: if self.state_label is not None: self.state_label.setText(_( "<span style=\'color: #44AA44\'><b>Running...</b></span>")) self.t0 = time() self.timer.timeout.connect(self.show_time) self.timer.start(1000) else: if self.state_label is not None: self.state_label.setText(_('Terminated.')) try: self.timer.timeout.disconnect(self.show_time) except (RuntimeError, TypeError): pass def set_buttons_runnning_state(self, state): self.run_button.setVisible(not state and not self.is_ipykernel) self.kill_button.setVisible(state) @Slot(bool) def start_shell(self, ask_for_arguments=False): """Start shell""" if ask_for_arguments and not self.get_arguments(): self.set_running_state(False) return try: self.terminate_button.clicked.disconnect(self.process.terminate) self.kill_button.clicked.disconnect(self.process.terminate) except (AttributeError, RuntimeError, TypeError): pass self.create_process() @Slot() def get_arguments(self): arguments, valid = QInputDialog.getText(self, _('Arguments'), _('Command line arguments:'), QLineEdit.Normal, self.arguments) if valid: self.arguments = to_text_string(arguments) return valid def create_process(self): raise NotImplementedError def finished(self, exit_code, exit_status): self.shell.flush() self.sig_finished.emit() if self.is_closing: return self.set_running_state(False) self.show_time(end=True) #=============================================================================== # Input/Output #=============================================================================== def transcode(self, qba): try: return to_text_string(qba.data(), 'utf8') except UnicodeDecodeError: return qba.data() def get_stdout(self): self.process.setReadChannel(QProcess.StandardOutput) qba = QByteArray() while self.process.bytesAvailable(): qba += self.process.readAllStandardOutput() return self.transcode(qba) def get_stderr(self): self.process.setReadChannel(QProcess.StandardError) qba = QByteArray() while self.process.bytesAvailable(): qba += self.process.readAllStandardError() return self.transcode(qba) def write_output(self): # if we are already writing something else, # store the present message in a buffer if not self.write_lock.tryLock(): self.buffer_lock.lock() self.buffer.append(self.get_stdout()) self.buffer_lock.unlock() if not self.write_lock.tryLock(): return self.shell.write(self.get_stdout(), flush=True) while True: self.buffer_lock.lock() messages = self.buffer self.buffer = [] if not messages: self.write_lock.unlock() self.buffer_lock.unlock() return self.buffer_lock.unlock() self.shell.write("\n".join(messages), flush=True) def send_to_process(self, qstr): raise NotImplementedError def send_ctrl_to_process(self, letter): char = chr("abcdefghijklmnopqrstuvwxyz".index(letter) + 1) byte_array = QByteArray() byte_array.append(char) self.process.write(byte_array) self.process.waitForBytesWritten(-1) self.shell.write(LOCALE_CODEC.toUnicode(byte_array), flush=True) def keyboard_interrupt(self): raise NotImplementedError
class BipapThread(QObject): signal = Signal(str) def __init__(self, serl, codegen, que): self.pressureque = que self.serl = serl self.codegen = codegen self.codegen.GenerateCMV() self.codelist = self.codegen.gcodestr.splitlines() self.linecount = len(self.codelist) self.flagStop = False self.pause = True self.gcode_exec_state = GcodeStates.READY_TO_SEND self.gcode_move_count = 0 self.presentPosition = (0,0) self.Tic = 0 self.Toc = 0 self.xyIncr = self.codegen.Dt self.gstr = "" self.sremsg = "" self.serialmutex = QMutex() self.startdelay = -1 super().__init__() def gcodestep(self): self.gstr = "G01 X" + str(self.xyIncr) + " Y" + str(self.xyIncr) + " F1000\r\n" if self.xyIncr < self.codegen.xmax: self.xyIncr += 1 def Stop(self): self.flagStop = True def updateGcode(self, codegen): self.codegen = codegen self.codegen.GenerateCMV() self.codelist = self.codegen.gcodestr.splitlines() def StartMoving(self): self.pause = False def StartMovingAfter(self, delay): self.startdelay = delay def StopMoving(self): self.pause = True self.xyIncr = self.codegen.Dt @Slot() def run(self): lst = [] while 1: if self.flagStop: break try: if not self.pause: if self.gcode_exec_state == GcodeStates.READY_TO_SEND: self.gcodestep() self.serialmutex.lock() self.serl.write(self.gstr.encode("utf-8")) self.serialmutex.unlock() self.gcode_move_count += 1 if self.gcode_move_count >= 130: #self.pause = True self.gcode_move_count = 0 else: self.gcode_exec_state = GcodeStates.WAIT_FOR_TIMEOUT self.Tic = time.perf_counter() if self.gcode_exec_state == GcodeStates.WAIT_FOR_TIMEOUT: if (time.perf_counter() - self.Tic) >= 0.15: #print("Gcode Executed\r\n") self.gcode_exec_state = GcodeStates.READY_TO_SEND elif self.startdelay > 0: time.sleep(self.startdelay) self.startdelay = -1 self.pause = False except serial.SerialException as ex: print("Error In SerialException" + str(ex.strerror))
class SegmentationThread(QThread): """ Method to run calculation task in separated Thread. This allows to not freeze main window. To get info if calculation is done connect to :py:meth:`~.QThread.finished`. """ execution_done = Signal(SegmentationResult) """ Signal contains result of segmentation algorithm. Emitted if calculation ends without exception and :py:meth:`SegmentationAlgorithm.calculation_run` return not None result. """ progress_signal = Signal(str, int) """ Signal with information about progress. This is proxy for :py:meth:`SegmentationAlgorithm.calculation_run` `report_fun` parameter` """ info_signal = Signal(str) exception_occurred = Signal(Exception) """Signal emitted when some exception occur during calculation. """ def __init__(self, algorithm: SegmentationAlgorithm): super().__init__() self.finished.connect(self.finished_task) self.algorithm = algorithm self.clean_later = False self.cache = None self.mutex = QMutex() self.rerun = False, QThread.InheritPriority def get_info_text(self): """Proxy for :py:meth:`.SegmentationAlgorithm.get_info_text`.""" return self.algorithm.get_info_text() def send_info(self, text, num): self.progress_signal.emit(text, num) def run(self): """the calculation are done here""" if self.algorithm.image is None: # assertion for running algorithm without image print(f"No image in class {self.algorithm.__class__}", file=sys.stderr) return try: segment_data = self.algorithm.calculation_run_wrap(self.send_info) except Exception as e: self.exception_occurred.emit(e) return if segment_data is None: return self.execution_done.emit(segment_data) def finished_task(self): """ Called on calculation finished. Check if cache is not empty. In such case start calculation again with new parameters. """ self.mutex.lock() if self.cache is not None: args, kwargs = self.cache self.algorithm.set_parameters(*args, **kwargs) self.cache = None self.clean_later = False if self.rerun[0]: self.rerun = False, QThread.InheritPriority super().start(self.rerun[1]) elif self.clean_later: self.algorithm.clean() self.clean_later = False self.mutex.unlock() def clean(self): """ clean cache if thread is running. Call :py:meth:`SegmentationAlgorithm.clean` otherwise. : """ self.mutex.lock() if self.isRunning(): self.clean_later = True else: self.algorithm.clean() self.mutex.unlock() def set_parameters(self, *args, **kwargs): """ check if calculation is running. If yes then cache parameters until it finish, otherwise call :py:meth:`.SegmentationAlgorithm.set_parameters` """ self.mutex.lock() if self.isRunning(): self.cache = args, kwargs self.clean_later = False else: self.algorithm.set_parameters(*args, **kwargs) self.mutex.unlock() def start(self, priority: "QThread.Priority" = QThread.InheritPriority): """ If calculation is running remember to restart it with new parameters. Otherwise start immediately. """ self.mutex.lock() if self.isRunning(): self.clean_later = False self.rerun = True, priority else: super().start(priority) self.mutex.unlock()