Home > Net >  Warping a infinite loop using ctypes
Warping a infinite loop using ctypes

Time:04-16

I have some dlls that control a hardware piece to acquire some information. They work by having a infinite loop that keeps doing constant acquisitions of new data every couple of seconds.

Is it possible to warp this infinite loop function so it can be called in python in parallel while other work is done (periodically checking the loop for new data)? Or would it be better to replicate the loop in python (I would need them to save all the current state of the C functions on each execution)?

In other words, I want to call this function and have it start acquiring and them every couple of seconds peak at the data (from python) to see it.

Bellow a minimal example

On C:

#include <stdio.h>
void loop()
{
    while( 1 )
    {
        GetNewData();
        sleep(1);
    }
}

On python:

import multiprocessing as mp
from multiprocessing.pool import Pool
from ctypes import *

def worker():
    lib = CDLL("test.dll")
    lib.loop()

def call(func):
    global p
    a = p.apply_async(func)
    a.get()       

if __name__ == '__main__':
    p = Pool(1)
    call(worker)
    DoSomethingElse() # Code never reaches this point.

CodePudding user response:

It sounds like you need a thread with a callback function and a way to stop it. Here's a rough example:

test.c

#ifdef _WIN32
#   define API __declspec(dllexport)
#else
#   define API
#endif

typedef void (*CALLBACK)(int);

int g_running;

API void run(CALLBACK cb) {
    g_running = 1;
    int data = 0;
    while(g_running)
        cb(data  );
}

API void stop() {
    g_running = 0;
}

test.py

import ctypes as ct
import threading
import time

# ctypes wrapper for a C function callback.
# returns None and takes an integer.
CALLBACK = ct.CFUNCTYPE(None,ct.c_int)

dll = ct.CDLL('./test')
dll.run.argtypes = CALLBACK,
dll.run.restype = None
dll.stop.argtypes = ()
dll.stop.restype = None

# decorate a Python function with the ctypes callback
# and it can be passed to a C function and called.
@CALLBACK
def callback(data):
    print(data)
    time.sleep(.1) # just to slow it down.

# start a thread with the run function.
t = threading.Thread(target=dll.run, args=(callback,))
t.start()

time.sleep(.2)
print('\tdoing')
time.sleep(.2)
print('\tsomething')
time.sleep(.2)
print('\telse')
time.sleep(.4)

# issue stop and wait for graceful exit of thread
dll.stop()
t.join()

Output:

0
1
        doing
2
3
        something
4
5
        else
6
7
8
9
  • Related