【问题标题】:Multithreading with Python and C api使用 Python 和 C api 进行多线程
【发布时间】:2015-04-12 22:10:08
【问题描述】:

我有一个 C++ 程序,它使用 C api 来使用我的 Python 库。 Python 库和 C++ 代码都是多线程的。

特别是,C++ 程序的一个线程实例化了一个继承自threading.Thread 的 Python 对象。我需要我的所有 C++ 线程能够调用该对象上的方法。

从我的第一次尝试(我天真地只是从主线程实例化对象,然后等待一段时间,然后调用该方法)我注意到与刚刚创建的对象关联的 Python 线程的执行一旦停止执行回到 C++ 程序。

如果继续使用 Python 执行(例如,如果我调用 PyRun_SimpleString("time.sleep(5)");),则 Python 线程会在后台继续执行,一切正常,直到等待结束并返回 C++。

我显然做错了什么。我应该怎么做才能使我的 C++ 和 Python 成为多线程的 both 并能够很好地相互协作?我之前没有该领域的经验,所以请不要假设任何事情!

【问题讨论】:

    标签: python c++ multithreading python-c-api


    【解决方案1】:

    执行您要执行的操作的正确步骤顺序是:

    • 在主线程中:

      1. 使用Py_Initialize*初始化Python。
      2. 使用 PyEval_InitThreads() 初始化 Python 线程支持。
      3. 启动 C++ 线程。

    此时,主线程仍然持有 GIL。

    • 在 C++ 线程中:
      1. 使用PyGILState_Ensure() 获取 GIL。
      2. 创建一个新的 Python 线程对象并启动它。
      3. 使用 PyGILState_Release() 发布 GIL。
      4. 睡觉,做一些有用的事情或退出线程。

    由于主线程持有 GIL,该线程将等待获取 GIL。如果主线程调用 Python API,它可能会不时释放 GIL,让 Python 线程执行一段时间。

    • 回到主线程:
      1. 释放 GIL,使线程能够使用PyEval_SaveThread() 运行
      2. 在尝试使用其他 Python 调用之前,请使用 PyEval_RestoreThread() 重新获取 GIL

    我怀疑你错过了最后一步——在主线程中释放 GIL,让 Python 线程执行。

    我在this link 有一个小而完整的示例。

    【讨论】:

      【解决方案2】:

      当你从python的threading.Thread回调时,你可能没有解锁Global Interpreter Lock

      好吧,如果你使用的是裸 python 的 C API,你有 some documentation here,关于如何释放/获取 GIL。但是在使用 C++ 时,我必须警告你,它可能会在你的 C++ 代码中抛出任何异常时崩溃。 See here.

      一般来说,任何运行时间过长的 C++ 函数都应该解锁 GIL 并锁定,只要它再次使用 C Python API。

      【讨论】:

      • 很抱歉,我似乎没有正确理解这一点。这是我所做的:1)PyGILState_STATE gstate; gstate = PyGILState_Ensure(); 2)创建从threading.Thread 继承的 python 对象 3)PyGILState_Release(gstate); 4)休眠几秒钟(在 C++ 中)在运行函数中,对象应该打印一次在一段时间内,但它显然只在最初的几毫秒内这样做。我在做什么错..?
      猜你喜欢
      • 2016-08-22
      • 1970-01-01
      • 1970-01-01
      • 2013-08-03
      • 1970-01-01
      • 1970-01-01
      • 2023-03-24
      • 1970-01-01
      • 2010-12-10
      相关资源
      最近更新 更多