2020-12-16 17:25:24 +08:00

205 lines
5.3 KiB
Python

# -*- coding:utf-8 -*-
#############################################################################
import sys
import os
import signal
import threading
from queue import Queue
from gspylib.inspection.common.Exception import InterruptException
class TaskThread(threading.Thread):
def __init__(self, queWork, queResult, iTimeout):
"""
function: constructor
"""
threading.Thread.__init__(self)
# timeout for fetching task
self.m_iTimeout = iTimeout
self.m_bRunning = True
self.setDaemon(True)
self.m_queWork = queWork
self.m_queResult = queResult
self.start()
def run(self):
"""
function: run method
input : NA
output : NA
"""
while self.m_bRunning:
if Queue is None:
break
try:
# fetch a task from the queue,
# here timout parameter MUST be asigned,
# otherwise get() will wait for ever
callableFun, args = self.m_queWork.get(timeout=self.m_iTimeout)
# run the task
Ret = callableFun(args[0])
self.m_queResult.put(Ret)
# if task queue is empty
except Exception:
self.m_bRunning = False
continue
class TaskPool:
def __init__(self, iNumOfThreads, iTimeOut=1):
"""
function: constructor
"""
self.m_queWork = Queue.Queue()
self.m_queResult = Queue.Queue()
self.m_lstThreads = []
self.m_iTimeOut = iTimeOut
self.__createThreadPool(iNumOfThreads)
def __createThreadPool(self, iNumOfThreads):
"""
function: create thread pool
input : iNumOfThreads
output : NA
"""
for i in range(iNumOfThreads):
aThread = TaskThread(self.m_queWork, self.m_queResult,
self.m_iTimeOut)
self.m_lstThreads.append(aThread)
# add a task into the thread pool
def addTask(self, callableFunc, *args):
"""
function: add task
input : callableFunc, *args
output : NA
"""
self.m_queWork.put((callableFunc, list(args)))
# get one task executing result
def getOneResult(self):
"""
function: get one result
input : NA
output : NA
"""
try:
# get a reult from queue,
# get will not return until a result is got
aItem = self.m_queResult.get()
return aItem
except Exception:
return None
# notify all theads in the thread pool to exit
def notifyStop(self):
"""
function: notify stop
input : NA
output : NA
"""
for aThread in self.m_lstThreads:
aThread.m_bRunning = False
# Waiting for all threads in the thread pool exit
def waitForComplete(self):
# wait all threads terminate
while len(self.m_lstThreads):
aThread = self.m_lstThreads.pop()
# wait the thread terminates
if aThread.isAlive():
aThread.join()
class Watcher:
"""
this class solves two problems with multithreaded
programs in Python, (1) a signal might be delivered
to any thread (which is just a malfeature) and (2) if
the thread that gets the signal is waiting, the signal
is ignored (which is a bug).
The watcher is a concurrent process (not thread) that
waits for a signal and the process that contains the
threads.
"""
def __init__(self):
"""
Creates a child thread, which returns.
The parent thread waits for a KeyboardInterrupt
and then kills the child thread.
"""
self.child = os.fork()
if self.child == 0:
return
else:
self.watch()
def watch(self):
"""
function: watch
input : NA
output : NA
"""
try:
os.wait()
except KeyboardInterrupt:
# I put the capital B in KeyBoardInterrupt so I can
# tell when the Watcher gets the SIGINT
self.kill()
raise InterruptException()
sys.exit()
def kill(self):
"""
function: kill
input : NA
output : NA
"""
os.kill(self.child, signal.SIGKILL)
class CheckThread(threading.Thread):
def __init__(self, name, func, *args):
"""
function: constructor
"""
super(CheckThread, self).__init__(name=name, target=func, args=args)
self._stop_event = threading.Event()
self.setDaemon(True)
self.exitcode = 0
self.exception = None
self.name = name
self.func = func
self.args = args
self.start()
def run(self):
"""
function: run
input : NA
output : NA
"""
try:
self.func(*self.args)
except Exception as e:
self.exitcode = 1
self.exception = e
def stop(self):
"""
function: stop
input : NA
output : NA
"""
self._stop_event.set()
def stopped(self):
"""
function: stopped
input : NA
output : NA
"""
return self._stop_event.is_set()