Обработка бесконечных циклов в функции ctypes с помощью Python - PullRequest
0 голосов
/ 20 марта 2020

Допустим, у меня есть несколько функций, определенных в C, одна из которых приводит к бесконечному l oop. Я использую модуль ctypes в Python для запуска каждой из этих функций, и, следовательно, это приводит к бесконечному l oop, что приводит к полной остановке в моем Python скрипте.

Я пытался запустить функцию C по таймауту, но тайм-аут никогда не срабатывает. Как мне справиться с этим? Я не могу остановить свой сценарий Python, если эта бесконечная функция l oop обнаружена, я должен напечатать сообщение об ошибке, а затем перейти к следующей функции. Тайм-аут выглядит примерно так:

limit = 10
def raise_timeout(signum, frame):
    raise TimeoutError

def timeout(limit):
    signal.signal(signal.SIGALARM, raise_timeout)
    signal.alarm(limit)
    try:
        yield
    except TimeoutError:
        print('Timed out')
    finally:
        signal.signal(signal.SIGALARM, signal.SIG_IGN)


## Attempting to run function

for function in function_list:

    #Perform actions to load the shared .so library, define res/argtypes etc

    with timeout(limit):
        result = c_lib() # This is the function I run from ctypes

Единственный способ, которым я вижу, - обработать его, используя таймер, например, 10 секунд или около того. Но я чувствую, что делаю это неправильно - есть ли способ для моего Python сценария выяснить, что функция ctypes не отвечает в течение 10 секунд, поэтому она должна как-то завершиться?

I ' Я в отчаянии, любая хакерская вещь, которая работает, но идет вразрез со здравым смыслом, тоже подойдет. : (

Любая помощь приветствуется, спасибо.

1 Ответ

1 голос
/ 21 марта 2020

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

Демо:

import multiprocessing as mp
from multiprocessing.pool import Pool

import time

def worker(work):
    time.sleep(work)  # pretend to do some work
    return work

def call(func,work_time,timeout):
    global p
    a = p.apply_async(func,(work_time,))  # call function using pool
    try:
        result = a.get(timeout)           # wait for asynchronous result
        print(f'{result=}')
    except mp.TimeoutError:
        p.terminate()                     # kill the pool
        p.join()                          # wait for the pool processes to stop
        print('Terminated.')
        p = Pool(1)                       # restart pool

if __name__ == '__main__':
    p = Pool(1)       # global process pool (1 process)
    call(worker,1,3)
    call(worker,2,3)
    call(worker,3,3)
    call(worker,4,3)
    p.close()         # Tell all processes in pool to stop
    p.join()          # Wait for them to stop.

Вывод:

result=1
result=2
Terminated.
Terminated.
...