Функция не работает при запуске мультипроцессором

#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!