2009-06-01 3 views
2

Wenn Sie ein KeyboardInterrupt auslösen, während Sie versuchen, ein Semaphor zu erwerben, hängen die Threads, die versuchen, dasselbe Semaphore-Objekt ebenfalls zu veröffentlichen, auf unbestimmte Zeit.BoundedSemaphore hängt in Threads auf KeyboardInterrupt

Code:

import threading 
import time 

def worker(i, sema): 
    time.sleep(2) 
    print i, "finished" 
    sema.release() 


sema = threading.BoundedSemaphore(value=5) 
threads = [] 
for x in xrange(100): 
    sema.acquire() 
    t = threading.Thread(target=worker, args=(x, sema)) 
    t.start() 
    threads.append(t) 

diese starten und dann^C, wie es läuft. Es wird hängen bleiben und niemals enden.

0 finished 
3 finished 
1 finished 
2 finished 
4 finished 
^C5 finished 
Traceback (most recent call last): 
    File "/tmp/proof.py", line 15, in <module> 
    sema.acquire() 
    File "/System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/threading.py", line 290, in acquire 
    self.__cond.wait() 
    File "/System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/threading.py", line 214, in wait 
    waiter.acquire() 
KeyboardInterrupt 
6 finished 
7 finished 
8 finished 
9 finished 

Wie kann ich es bekommen, dass die letzten paar Threads natürlichen Todes sterben und dann normal aussteigen? (Was es tut, wenn Sie nicht versuchen, es zu unterbrechen)

Antwort

2

Sie können die Signalmodul verwenden, um ein Flag zu setzen, die den Haupt-Thread sagt Verarbeitung zu stoppen:

import threading 
import time 
import signal 
import sys 

sigint = False 

def sighandler(num, frame): 
    global sigint 
    sigint = True 

def worker(i, sema): 
    time.sleep(2) 
    print i, "finished" 
    sema.release() 

signal.signal(signal.SIGINT, sighandler) 
sema = threading.BoundedSemaphore(value=5) 
threads = [] 
for x in xrange(100): 
    sema.acquire() 
    if sigint: 
    sys.exit() 
    t = threading.Thread(target=worker, args=(x, sema)) 
    t.start() 
    t.join() 
    threads.append(t) 
+0

Sicherlich mehr als 2 Personen Haben Sie dieses Problem, verdienen Sie weit mehr als 2 Stimmen. Ich frage mich, wie bist du auf diese Antwort gekommen? – num1

0

In diesem Fall sieht es aus Vielleicht möchten Sie einfach einen Thread-Pool verwenden, um das Starten und Stoppen Ihrer Threads zu steuern.

pool = ThreadPool(5) 
try: 
    # enqueue 100 worker threads 
    pool.wait() 
except KeyboardInterrupt, k: 
    pool.dismiss(5) 
    # the program will exit after all running threads are complete 
0

In Ihrem ursprünglichen Code, den Sie auch die Fäden Daemon-Threads machen könnte: Man könnte Chris Arndt's threadpool library in einer Art und Weise so etwas wie diese verwendet werden. Wenn Sie das Skript unterbrechen, werden alle Daemon-Threads wie erwartet beendet.

t = ... 
    t.setDaemon(True) 
    t.start() 
0

Dies ist Bug #11714 und hat patched in neueren Versionen von Python gewesen.

Wenn Sie eine ältere Python verwenden, können Sie die die Version von Semaphore in diesem Patch in Ihr Projekt gefunden kopieren und verwenden stattdessen auf die fehlerhafte Version der Berufung in threading

0
# importing modules 
import threading 
import time 
# defining our worker and pass a counter and the semaphore to it 
def worker(i, sema): 
    time.sleep(2) 
    print i, "finished" 
    # releasing the thread increments the sema value 
    sema.release() 

# creating the semaphore object 
sema = threading.BoundedSemaphore(value=5) 
# a list to store the created threads 
threads = [] 
for x in xrange(100): 
try: 
    sema.acquire() 
    t = threading.Thread(target=worker, args=(x, sema)) 
    t.start() 
    threads.append(t) 
# exit once the user hit CTRL+c 
# or you can make the thead as daemon t.setdaemon(True) 
except KeyboardInterrupt: 
    exit() 
+0

Können Sie bitte einen Kommentar für Ihren Code hinzufügen? – Zulu

+0

Hoffentlich hat es jetzt geholfen –

Verwandte Themen