我有一个嵌入式的python程序,它在c语言的一个线程中运行。
当python解释器切换线程上下文(将控制权交给另一个线程)时,我希望得到通知,以便可以执行某些必要的操作。
看来Py_AddPendingCall正是我要找的。然而,api文档对这个函数非常简短,我对如何使用Py_AddPendingCall感到困惑。通过阅读这些文档,我的理解是:
工作线程调用Py_AddPendingCall并分配处理程序
功能。
当python解释器运行时,它调用handler函数
每当它将控制权交给另一个线程时
处理程序本身在主解释器线程中执行,其中
吉尔获得了
我在google上搜索了一些演示如何使用Py_AddPendingCall的示例代码,但什么也找不到。我自己想用它根本不行。处理程序从未被调用。
我的工作线程代码:

#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>

const char* PYTHON_CODE =
"while True:\n"
"   for i in range(0,10): print(i)\n"
"\n";

int handler(void* arg)
{
    printf("Pending Call invoked!\n");
    abort();
}

void* worker_thread(void*)
{
    PyGILState_STATE state = PyGILState_Ensure();
    int res = Py_AddPendingCall(&func, nullptr);
    cout << "Result: " << res << endl;
    PyRun_SimpleString(CODE);
    PyGILState_Release(state);

    return 0;
}

int main()
{
    Py_Initialize();
    PyEval_InitThreads();
    PyEval_ReleaseLock();

    pthread_t threads[4];
    for (int i = 0; i < 4; ++i)
        pthread_create(&threads[i], 0, worker_thread, 0);

    for (int i = 0; i < 4; ++i) pthread_join(threads[i], 0);

    Py_Finalize();
}

在本例中,worker_thread在c中作为pthread工作线程被调用。在这个测试中,我运行了4个工作线程,因此应该进行一些上下文切换。这将无限循环,但挂起的调用处理程序永远不会被调用。
那么,有人能提供一个最小的工作示例来说明Py_AddPendingCall应该如何使用吗?

最佳答案

挂起的调用只在主线程上执行,并且主线程只能在执行python代码时为挂起的调用提供服务。因此,主线程必须运行一个解释器循环,以便为任何挂起的调用提供服务。从Python/ceval.c

Py_MakePendingCalls(void)
{
    ...

    /* only service pending calls on main thread */
    if (main_thread && PyThread_get_thread_ident() != main_thread)
        return 0;

    ...
}

在嵌入场景中,“主线程”是调用PyEval_InitThreads的线程(注意,当您第一次从python代码启动线程时,也会自动调用它)。因为您的主线程位于pthread_join中,所以它不会执行python代码,因此也不会分派挂起的调用。
还需要注意的是,处理程序只在将控件交给主线程时执行——如果控件从一个工作线程转到另一个工作线程,则处理程序不会运行。因此,Py_MakePendingCalls可能不是用于此任务的适当接口。

07-25 22:56
查看更多