205 lines
5.3 KiB
Python
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()
|