#python #multiprocessing
Вопрос:
У меня есть функция C, которая выделяет целое число, передает указатель на функцию обратного вызова, прежде чем возвращать указатель.
void change_state(int gpio, int level, uint32_t tick, void *ptr){ if (level == 1){ printf("Button was pressed!n"); *((int*)ptr) = 1; } } int * allocate_void_ptr_start_watchdog(int BUTTON){ void *current_state_ptr = malloc(sizeof(int)); /*Creates a ptr of size int*/ *((int*)current_state_ptr) = 0; /*Casts ptr to type int and set to 0*/ gpioSetAlertFuncEx(BUTTON, change_state, current_state_ptr); /*Function to watch for GPIO state change*/ return current_state_ptr; }
Возвращаемое значение затем передается обратно в Python:
allocate_ptr_start_watchdog = button_functions.allocate_void_ptr_start_watchdog allocate_ptr_start_watchdog.restype = ctypes.POINTER(ctypes.c_int) ptr = allocate_ptr_start_watchdog(BUTTON)
Использование while True
цикла следующим образом работает, как и ожидалось (1 нажатие кнопки на GPIO 25 включит свет, второе нажатие выключит его)
while True: current_val = ptr.contents.value if current_val == 0: continue elif current_val == 1: button_functions.turn_on_lights(LED_1, LED_2) else: button_functions.clear_all(LED_1, LED_2) ptr.contents.value = 0
Однако, как только я пытаюсь использовать многопроцессорную обработку, функция прерывается, так как нажатие кнопки больше не включает и не выключает свет. Тем не менее, printf
из библиотеки C все еще печатается, поэтому я сомневаюсь, что это проблема с библиотекой.
def button_start(ptr): while True: current_val = ptr.contents.value if current_val == 0: continue elif current_val == 1: button_functions.turn_on_lights(LED_1, LED_2) else: button_functions.clear_all(LED_1, LED_2) ptr.contents.value = 0 multiprocessing.Process(target=button_start, args=(ptr,)).start()
Это работает на Raspbian Buster с ядром 5.10.63-v7l . Что я упускаю/не вижу здесь?
Комментарии:
1. Не могли бы вы сказать нам, на какой операционной системе вы это используете?
multiprocessing
использует другой механизм порождения (fork
а неspawn
) в системах Linux, и это может повлиять на способ загрузки вашего кода.2. @SilvioMayolo В настоящее время работает код в Linux, точнее, Raspbian buster, ядро 5.10.63. На самом деле в этом и проблема, у меня есть еще одна часть в моем коде, которая также вызывает многопроцессорную обработку, которая работает нормально, но эта часть представляет собой цикл python while.
3. что произойдет, если вы переместите весь код взаимодействия c в многопроцессорный fn? т. е. определите ptr в многопроцессорном fn, а не передавайте его. также добавьте некоторую отладку в свой fn: печатайте, когда он получает значение, и когда он пытается включить или выключить свет, чтобы вы могли видеть, что именно не работает.
4. Кстати, обычно можно получить доступ к gpio из python или через виртуальные файлы
/sys/class/gpio
. Это обходной путь, и то, что вы делаете, тоже должно быть возможным, но, возможно, стоит попробовать. (полностью избегая кода c).5. @2e0byo У меня есть ограничение, связанное с необходимостью работать с GPIO только с C. Однако я понял, что, похоже, происходит то, что, поскольку дочерний процесс не находится в том же состоянии, что и родительский процесс, в MP-версии кода функция watchdog не обновляет ptr.
Ответ №1:
Поскольку процессу MP необходимо подключиться обратно к демону pigpio, должна быть функция, которая выполняет это.
int connect_to_daemon(){ /*Connect to pigpio daemon*/ printf("Connecting to daemonn"); int daemon_instance = pigpio_start("192.168.86.234", NULL); printf("Successfully connected to daemonn"); return daemon_instance; }
Затем мы можем назначить переменную этому экземпляру в Python daemon_instance = button_function.connect_to_daemon()
перед вызовом нашей функции обратного вызова.
int * start_callback(int daemon_instance, int BUTTON){ void *current_state_ptr = malloc(sizeof(int)); /*Creates a ptr of size int*/ *((int*)current_state_ptr) = 0; /*Casts ptr to type int and set to 0*/ callback_ex(daemon_instance, BUTTON, FALLING_EDGE, change_state, current_state_ptr); return current_state_ptr; }
На языке Python:
ptr = button_functions.start_callback(daemon_instance, BUTTON) print(ptr.contents.value) # This should return the correct value now
Большое спасибо 2e0byo!