Есть ли способ убить нить? - PullRequest
666 голосов
/ 27 ноября 2008

Возможно ли завершить работающий поток без установки / проверки каких-либо флагов / семафоров / и т.

Ответы [ 24 ]

0 голосов
/ 14 апреля 2016

Вы можете выполнить свою команду в процессе, а затем уничтожить ее, используя идентификатор процесса. Мне нужно было синхронизировать два потока, один из которых не возвращает сам по себе.

processIds = []

def executeRecord(command):
    print(command)

    process = subprocess.Popen(command, stdout=subprocess.PIPE)
    processIds.append(process.pid)
    print(processIds[0])

    #Command that doesn't return by itself
    process.stdout.read().decode("utf-8")
    return;


def recordThread(command, timeOut):

    thread = Thread(target=executeRecord, args=(command,))
    thread.start()
    thread.join(timeOut)

    os.kill(processIds.pop(), signal.SIGINT)

    return;
0 голосов
/ 09 февраля 2018

Питер Хинтдженс - один из основателей ØMQ -проекта - говорит, что использование ØMQ и избегание примитивов синхронизации, таких как блокировки, мьютексы, события и т. Д., Является самым разумным и безопасным способом написания нескольких программы:

http://zguide.zeromq.org/py:all#Multithreading-with-ZeroMQ

Это включает в себя указание дочернему потоку, что он должен отменить свою работу. Это можно сделать, оснастив поток сокетом ØMQ и опросив на нем сокет, чтобы получить сообщение о том, что он должен быть отменен.

Ссылка также содержит пример многопоточного кода Python с ØMQ.

0 голосов
/ 24 ноября 2017

Хотя он довольно старый, , для некоторых может оказаться удобным решением:

Маленький модуль, который расширяет функциональность модуля потоков - позволяет одному потоку вызывать исключения в контексте другого нить. Подняв SystemExit, вы можете наконец убить потоки Python.

import threading
import ctypes     

def _async_raise(tid, excobj):
    res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, ctypes.py_object(excobj))
    if res == 0:
        raise ValueError("nonexistent thread id")
    elif res > 1:
        # """if it returns a number greater than one, you're in trouble, 
        # and you should call it again with exc=NULL to revert the effect"""
        ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, 0)
        raise SystemError("PyThreadState_SetAsyncExc failed")

class Thread(threading.Thread):
    def raise_exc(self, excobj):
        assert self.isAlive(), "thread must be started"
        for tid, tobj in threading._active.items():
            if tobj is self:
                _async_raise(tid, excobj)
                return

        # the thread was alive when we entered the loop, but was not found 
        # in the dict, hence it must have been already terminated. should we raise
        # an exception here? silently ignore?

    def terminate(self):
        # must raise the SystemExit type, instead of a SystemExit() instance
        # due to a bug in PyThreadState_SetAsyncExc
        self.raise_exc(SystemExit)

Таким образом, он позволяет «потоку вызывать исключения в контексте другого потока», и, таким образом, завершенный поток может обрабатывать завершение без регулярной проверки флага прерывания.

Однако, согласно исходному источнику , с этим кодом есть некоторые проблемы.

  • Исключение будет вызываться только при выполнении байт-кода Python. Если ваш поток вызывает встроенную / встроенную функцию блокировки, исключение будет возбуждено только тогда, когда выполнение вернется к питону код.
    • Существует также проблема, если встроенная функция внутренне вызывает PyErr_Clear (), что фактически отменяет ожидающее исключение. Вы можете попытаться поднять его снова.
  • Только типы исключений могут быть вызваны безопасно. Экземпляры исключений могут вызывать неожиданное поведение и поэтому ограничены.
  • Я попросил выставить эту функцию во встроенном модуле потока, но поскольку ctypes стала стандартной библиотекой (начиная с 2.5), и это
    функция, скорее всего, не зависит от реализации, ее можно сохранить
    неразоблаченный.
0 голосов
/ 17 мая 2016

Запустите подпоток с помощью setDaemon (True).

def bootstrap(_filename):
    mb = ModelBootstrap(filename=_filename) # Has many Daemon threads. All get stopped automatically when main thread is stopped.

t = threading.Thread(target=bootstrap,args=('models.conf',))
t.setDaemon(False)

while True:
    t.start()
    time.sleep(10) # I am just allowing the sub-thread to run for 10 sec. You can listen on an event to stop execution.
    print('Thread stopped')
    break
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...