多子解释器通过Python C API导入特定模块时触发内存损坏错误
问题现象
我编写了单线程C++代码,借助Python C API启动两个子解释器Sub1和Sub2,随后在两个子解释器中加载模块M。当M导入urllib.request、yaml等特定模块时,若Sub1已完成M的导入,Sub2导入M会触发内存损坏错误;但如果M导入的是urllib、base64、os等模块则可正常运行。
C++代码实现
Py_Initialize(); PyThreadState *tstate_main, *tstate_s1, *tstate_s2; tstate_main = PyThreadState_Get(); std::cerr << "tstate_main: " << tstate_main << std::endl; //PyGILState_STATE gstate = PyGILState_Ensure(); PyInterpreterConfig config_s1 = { .use_main_obmalloc = 0, .allow_fork = 0, .allow_exec = 0, .allow_threads = 0, .allow_daemon_threads = 0, .check_multi_interp_extensions = 1, .gil = PyInterpreterConfig_OWN_GIL, }; tstate_s1 = NULL; PyStatus status_s1 = Py_NewInterpreterFromConfig(&tstate_s1, &config_s1); std::cerr << "tstate_s1: " << tstate_s1 << std::endl; std::string sysPathCmd1 = "import sys\nsys.path.append('" + cwd + "')"; PyRun_SimpleString(sysPathCmd1.c_str()); PyObject* bytecode1 = Py_CompileString(module_code1, "test_module1", Py_file_input); PyObject* pModule1 = PyImport_ExecCodeModule("test_module1", bytecode1); if(!pModule1) { std::cerr << "Error on module import:" << std::endl; PyErr_Print(); return -1; } PyObject* pFunc1 = PyObject_GetAttrString(pModule1, "test_call"); PyObject* pData1 = PyUnicode_FromString("hello"); PyObject* pArgs1 = PyTuple_Pack(1, pData1); PyObject* pResult1 = PyObject_CallObject(pFunc1, pArgs1); PyEval_RestoreThread(tstate_main); //PyGILState_STATE gstate = PyGILState_Ensure(); PyInterpreterConfig config_s2 = { .use_main_obmalloc = 0, .allow_fork = 0, .allow_exec = 0, .allow_threads = 0, .allow_daemon_threads = 0, .check_multi_interp_extensions = 1, .gil = PyInterpreterConfig_OWN_GIL, }; tstate_s2 = NULL; PyStatus status_s2 = Py_NewInterpreterFromConfig(&tstate_s2, &config_s2); std::cerr << "tstate_s2: " << tstate_s2 << std::endl; std::string sysPathCmd2 = "import sys\nsys.path.append('" + cwd + "')"; PyRun_SimpleString(sysPathCmd2.c_str()); PyObject* bytecode2 = Py_CompileString(module_code2, "test_module2", Py_file_input); PyObject* pModule2 = PyImport_ExecCodeModule("test_module2", bytecode2); PyObject* pFunc2 = PyObject_GetAttrString(pModule2, "test_call"); PyObject* pData2 = PyUnicode_FromString(""); PyObject* pArgs2 = PyTuple_Pack(1, pData2); PyObject* pResult2 = PyObject_CallObject(pFunc2, pArgs2); PyEval_RestoreThread(tstate_main);
Python测试代码
# import yaml # ERROR # import urllib.request # ERROR # import urllib # NO ERROR # import os # NO ERROR # import os.path # NO ERROR # import base64 # NO ERROR def test_call(data): print("Called")
内容的提问来源于stack exchange,提问作者Michele Agostini
相关产品推荐
相关产品推荐

