由多进程启动时功能不起作用

Posted

技术标签:

【中文标题】由多进程启动时功能不起作用【英文标题】:Function does not work when started by multiprocess 【发布时间】:2021-12-22 03:54:44 【问题描述】:

我有一个 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 循环按预期工作(按 GPIO 25 处的按钮 1 次将打开灯,第二次按将其关闭)

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

但是,一旦我尝试使用多处理功能,该功能就会中断,因为按下按钮不再打开或关闭灯。但是,C 库中的 printf 仍然可以打印,所以我怀疑这是库的问题。

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()

这是在内核 5.10.63-v7l+ 的 Raspbian Buster 上运行的。我在这里错过/看不到什么?

【问题讨论】:

介意告诉我们您在什么操作系统上运行它吗? multiprocessing 在 Linux 系统上使用不同的生成机制(fork 而不是 spawn),这可能会影响代码的加载方式。 @SilvioMayolo 目前在 Linux 上运行代码,更具体地说是 Raspbian buster,内核是 5.10.63。实际上这是问题所在,我的代码中有另一部分也调用多处理,它工作正常,但那部分是 python while 循环。 如果将所有 c 交互代码移动到多处理fn 会发生什么?即在多处理 fn 中定义 ptr,而不是传递它。还为你的 fn 添加一些调试:当它得到值时打印,当它试图打开或关闭灯时,这样你就可以看到到底是什么失败了。 顺便说一句,通常可以从 python 或通过/sys/class/gpio 中的虚拟文件获取 gpio 访问权限。这是一种解决方法,您正在做的事情也应该是可能的,但它可能值得尝试。 (完全避免使用 c 代码)。 @2e0byo 我有一个限制,只能使用 C 来使用 GPIO。但是我意识到似乎正在发生的事情是因为子进程与父进程不共享相同的状态过程中,代码的 MP 版本的 ptr 没有被看门狗函数更新。 【参考方案1】:

由于 MP 进程需要连接回 pigpio 守护进程,因此需要一个函数来执行该操作。

int connect_to_daemon() /*Connect to pigpio daemon*/
    printf("Connecting to daemon\n");
    int daemon_instance = pigpio_start("192.168.86.234", NULL);
    printf("Successfully connected to daemon\n");
    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!

【讨论】:

以上是关于由多进程启动时功能不起作用的主要内容,如果未能解决你的问题,请参考以下文章

进程启动但在使用 CreateProcessLogonW 或类似方法启动时不起作用

当 startet 退出事件时,在 C# 中启动 sqlcmd 进程不起作用

PHP启动的Bash后台进程不起作用

电子登录助手不起作用 - “进程不在继承的沙箱中”

从 Windows 服务调用时 Process.Start 不起作用

views.py 中的子进程不起作用