Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
539 views
in Technique[技术] by (71.8m points)

multithreading - Interruptible thread join in Python

Is there any way to wait for termination of a thread, but still intercept signals?

Consider the following C program:

#include <signal.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <pthread.h>
#include <stdlib.h>

void* server_thread(void* dummy) {
    sleep(10);
    printf("Served
");
    return NULL;
}

void* kill_thread(void* dummy) {
    sleep(1); // Let the main thread join
    printf("Killing
");
    kill(getpid(), SIGUSR1);
    return NULL;
}

void handler(int signum) {
    printf("Handling %d
", signum);
    exit(42);
}

int main() {
    pthread_t servth;
    pthread_t killth;

    signal(SIGUSR1, handler);

    pthread_create(&servth, NULL, server_thread, NULL);
    pthread_create(&killth, NULL, kill_thread, NULL);

    pthread_join(servth, NULL);

    printf("Main thread finished
");
    return 0;
}

It ends after one second and prints:

Killing
Handling 10

In contrast, here's my attempt to write it in Python:

#!/usr/bin/env python
import signal, time, threading, os, sys

def handler(signum, frame):
    print("Handling " + str(signum) + ", frame:" + str(frame))
    exit(42)
signal.signal(signal.SIGUSR1, handler)

def server_thread():
    time.sleep(10)
    print("Served")
servth = threading.Thread(target=server_thread)
servth.start()

def kill_thread():
    time.sleep(1) # Let the main thread join
    print("Killing")
    os.kill(os.getpid(), signal.SIGUSR1)
killth = threading.Thread(target=kill_thread)
killth.start()

servth.join()

print("Main thread finished")

It prints:

Killing
Served
Handling 10, frame:<frame object at 0x12649c0>

How do I make it behave like the C version?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Threads in Python are somewhat strange beasts given the global interpreter lock. You may not be able to achieve what you want without resorting to a join timeout and isAlive as eliben suggests.

There are two spots in the docs that give the reason for this (and possibly more).

The first:

From http://docs.python.org/library/signal.html#module-signal:

Some care must be taken if both signals and threads are used in the same program. The fundamental thing to remember in using signals and threads simultaneously is: always perform signal() operations in the main thread of execution. Any thread can perform an alarm(), getsignal(), pause(), setitimer() or getitimer(); only the main thread can set a new signal handler, and the main thread will be the only one to receive signals (this is enforced by the Python signal module, even if the underlying thread implementation supports sending signals to individual threads). This means that signals can’t be used as a means of inter-thread communication. Use locks instead.

The second, from http://docs.python.org/library/thread.html#module-thread:

Threads interact strangely with interrupts: the KeyboardInterrupt exception will be received by an arbitrary thread. (When the signal module is available, interrupts always go to the main thread.)

EDIT: There was a decent discussion of the mechanics of this on the python bug tracker here: http://bugs.python.org/issue1167930. Of course, it ends with Guido saying: " That's unlikely to go away, so you'll just have to live with this. As you've discovered, specifying a timeout solves the issue (sort of)." YMMV :-)


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...