【问题标题】:Python threads in CC语言中的Python线程
【发布时间】:2011-09-29 13:48:09
【问题描述】:

我正在用 C 编写一个多线程程序。在创建线程之前,通过调用 Py_Initialize() 初始化全局 python 环境。然后,在每个创建的线程中,共享全局python环境,每个线程调用一个python方法,并将参数转换为C。一切正常,直到这里。

当我在加载的 python 模块中使用time.sleep() 时,C 程序会引发Segmentation Fault。此外,加载的 python 模块应该加载另一个 C 库以继续工作。我编写了以下愚蠢的计数器库来测试它:

# python part, call the counter function
lib = ctypes.cdll.LoadLibrary(libpycount.so)
for i in xrange(10):
    lib.count()
// C part, dummy countings
#include <stdio.h>
int counter = 1;
void
count() {
    printf("counter:%d \n", counter);
    counter++;
}

我想这可能是因为我没有以正确的方式管理复杂的线程创建。我在 python 文档中找到了Non-Python created threads

有什么想法或建议吗?

【问题讨论】:

  • 您是否真的按照您找到的文档中的建议进行操作?您如何在调用 Python 的代码中获取 GIL?
  • @Thomas Wouters 我用过文档中提到的PyGILState_STATE gstate;gstate = PyGILState_Ensure();PyGILState_Release(gstate);

标签: python c multithreading


【解决方案1】:

问题是 Python 解释器是否是线程安全的——这就是文档所说的在同一进程空间中运行多个解释器的内容;

错误和警告:因为子解释器(和主解释器) 是同一过程的一部分,它们之间的绝缘不是 完美——例如,使用低级文件操作,如 os.close() 他们可以(意外或恶意)影响彼此的 打开文件。由于扩展名之间共享的方式 (子)解释器,某些扩展可能无法正常工作;这是 当扩展使用(静态)全局时尤其可能 变量,或者当扩展操作其模块的字典时 在其初始化之后。可以插入创建的对象 一个子解释器进入另一个子解释器的命名空间;这 应该非常小心地避免共享用户定义的 子解释器之间的函数、方法、实例或类, 因为此类对象执行的导入操作可能会影响错误 (子)解释器加载模块的字典。 (XXX 这是一个 难以修复的错误,将在未来的版本中解决。)

...而且我认为 Python 线程与 C/C++ 中的原生线程不同

【讨论】:

    【解决方案2】:

    我的问题已经解决了。您可能有更具体的问题,所以我在这里尝试以更通用的方式编写我的解决方案。希望对您有所帮助。


    - 在主 C 线程中

    • 一开始就初始化 Python 环境:
    /*define a global variable to store the main python thread state*/
    PyThreadState * mainThreadState = NULL;
    
    if(!Py_IsInitialized())
        Py_Initialize();
    
    mainThreadState = = PyThreadState_Get();
    
    • 然后启动C线程:
    pthread_create(pthread_id, NULL, thread_entrance, NULL);
    



    - 在每个线程中,或者我们可以说在 thread_entrance 函数的主体中

    • 准备环境:
    /*get the lock and create new python thread state*/
    PyEval_AcquireLock();
    PyInterpreterState * mainInterpreterState = mainThreadState->interp;
    PyThreadState * myThreadState = PyThreadState_New(mainInterpreterState);
    PyEval_ReleaseLock();    /*don't forget to release the lock*/
    
    /*
     * some C manipulations here
     */
    
    • 将嵌入的 Python 代码放在这里:
    /*get the lock and put your C-Python code here*/
    PyEval_AcquireLock();
    PyThreadState_Swap(myThreadState);    /*swap your python thread state*/
    
    PyEval_CallObject(py_function, py_arguments);
    /*or just something like PyRun_SimpleString("print \"hello world\""); for test*/
    
    PyThreadState_Swap(NULL);    /*clean the thread state before leaving*/
    PyEval_ReleaseLock();
    



    - 回到主 C 线程

    • 当每个线程完成他们的工作时,完成 python 环境
    pthread_join(pthread_id, NULL);
    PyEval_RestoreThread(mainThreadState);
    Py_Finalize();
    

    【讨论】:

      猜你喜欢
      • 2021-01-03
      • 1970-01-01
      • 2013-06-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多