[英]Synchronizing embedded Python in multi-threaded program
以下是在多线程程序中使用Python解释器的示例:
#include <python.h>
#include <boost/thread.hpp>
void f(const char* code)
{
static volatile auto counter = 0;
for(; counter < 20; ++counter)
{
auto state = PyGILState_Ensure();
PyRun_SimpleString(code);
PyGILState_Release(state);
boost::this_thread::yield();
}
}
int main()
{
PyEval_InitThreads();
Py_Initialize();
PyRun_SimpleString("x = 0\n");
auto mainstate = PyEval_SaveThread();
auto thread1 = boost::thread(f, "print('thread #1, x =', x)\nx += 1\n");
auto thread2 = boost::thread(f, "print('thread #2, x =', x)\nx += 1\n");
thread1.join();
thread2.join();
PyEval_RestoreThread(mainstate);
Py_Finalize();
}
它看起来很好,但它没有同步。 Python解释器在PyRun_SimpleString期间多次释放并重新获取GIL(参见docs,p。#2 )。
我们可以使用我们自己的同步对象来序列化PyRun_SimpleString调用,但这是一种错误的方法。
Python有自己的同步模块_thread
和threading
。 但它们不适用于此代码:
Py_Initialize();
PyRun_SimpleString(R"(
import _thread
sync = _thread.allocate_lock()
x = 0
)");
auto mainstate = PyEval_SaveThread();
auto thread1 = boost::thread(f, R"(
with sync:
print('thread #1, x =', x)
x += 1
)");
File "<string>", line 3, in <module> NameError: name '_[1]' is not defined
和死锁。 如何同步嵌入式python代码最有效的方法?
当CPython调用可能阻塞(或重新输入Python)的函数时,它会在调用函数之前释放全局解释器锁,然后在函数返回后重新获取锁。 在您的代码中,您调用内置的print
函数会导致释放解释器锁并运行另一个线程(请参阅string_print
中的string_print )。
所以你需要自己的锁:全局解释器锁不适合确保执行I / O的Python代码的序列化。
由于您正在使用Boost线程框架,因此您可能不会发现使用Boost 线程同步原语之一最方便,例如boost::interprocess::interprocess_mutex
。
[编辑:我的原始答案是错误的,正如Abyx指出的那样。]
with
语句在Python 3.1中有问题 ,但它在Python 3.2和Python 2.7中得到修复。
因此,正确的解决方案是使用threading
模块进行同步。
为了避免这样的问题,不应该使用在globals字典中使用临时变量的多线程代码,或者为每个线程使用不同的全局字典。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.