Let's say I have a several functions defined in C, one of which results in an infinite loop. I am using the ctypes module in Python to run each of these functions, and hence it results in an infinite loop resulting to a complete halt in my Python script.
I tried to run the C function under a timeout, but the timeout never gets triggered. How do I handle this? I cannot stop my Python script, if this infinite loop function is encountered, my requirement is to to print an error message, then continue with the next function. The timeout looks something like this:
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
The only way I see is to handle it using a timer, for example, 10 seconds or so. But I feel like I'm doing this wrong - is there any way for my Python script to figure out that the ctypes function hasn't responded for 10 seconds, therefore it should exit somehow?
I'm desperate here, any sort of hacky thing that works but goes against common sense is also fine. :(
Any help is appreciated, thanks.
If the C code hangs, Python doesn't regain control as far as I know. You could try calling the function using a multiprocessing pool.
Demo:
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.
Output:
result=1
result=2
Terminated.
Terminated.