1

Python で小さなスレッド化の例を書きました。スレッド内で例外が発生すると、そのスレッドが実行され続け、終了しないという問題に直面しています。私は次のコードを持っています:

class Producer (threading.Thread):

    def __init__(self, threadId):
        threading.Thread.__init__(self)
        self.threadId  = threadId
        self.killReceived = False

    def produce(self):
        while 1:
            if self.killReceived == True:
                print self.threadId+"inside kill section"
                return False
            print "running"
            time.sleep(1) 
            raise Exception('boo')

    def run(self):
        try:
            self.produce()
        except Exception as e:
            ThreadManager.getInstance().shutdown(self.threadId)

    def stop(self):
        self.killReceived = True

class ThreadManager:
    _instance = None

    @staticmethod
    def getInstance():
        if ThreadManager._instance == None:
            ThreadManager._instance = ThreadManager()
        return ThreadManager._instance

    def __init__(self):
        ''' some initializations '''

    def shutdown(self, threadId):
        while threading.active_count() > 1:
            for thread in threading.enumerate():    
                if type(thread) != threading._MainThread: #never kill main thread directly
                    thread.stop()
                    #print thread.threadId+" is alive? "+str(thread.isAlive())

プロデューサー内で例外を発生させると、キャッチされ、ThreadManager のシャットダウン メソッドを起動します。これにより、メイン スレッドを除くすべての実行中のスレッドの stop() メソッドが呼び出されます。コンシューマーはこの戦略を使用して終了しますが、プロデューサーはハングします。メソッドを実行isAliveすると、プロデューサー スレッドがまだ実行されていることがわかりますが、実行メソッドは実行されていません。run() 内runningにあるメソッドから .As exception が出力されなくなったため、スレッドは自動的に終了するはずです。produceしかし、そうではありません。では、プロデューサーはどこにいるのでしょうか?何らかの例外が発生したときに停止するにはどうすればよいですか?

4

1 に答える 1

2

ThreadManagershutdownが正しく同期されていません。基本的に、threading.active_count() > 1終了することのない while ループです。2 つ以上のスレッドがこのメソッドで終了した場合、それら (およびプログラム) は決して終了しません。

ランダムなスレッドを継続的に呼び出すのではなく (自分のスレッドに関連していない可能性もあります)、開始されたすべてのスレッドのインベントリを ThreadManager に保持し、stopそれぞれのスレッドを 1 回呼び出します。また、実際に stop を呼び出すコードは、それが論理的に属している ThreadManager に移動する必要があります。

さらに、ThreadManager.getInstanceスレッドセーフではありません。現状では、複数の ThreadManagers になる可能性があります。ロックを使用する必要があります。

全体として、 を再実装しているように見えますThreadPoolExecutor。代わりにそれを使用しないのはなぜですか?

于 2012-12-05T12:31:42.963 に答える