You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python 3.12 C-API结合OpenMP调用PyUnicode_FromString出现段错误

问题原因与解决方法

核心原因

Python 3.12对内存分配子系统(obmalloc)做了硬性变更:所有涉及Python对象内存分配的操作,要求当前线程必须关联有效的Python解释器状态与GIL(全局解释器锁)。

你的代码中,OpenMP创建的线程(哪怕通过#pragma omp single限定单线程执行)并未被Python线程机制初始化:

  • 单字符字符串"a"触发了Python的小对象缓存机制,不需要走完整的_PyObject_Malloc流程,因此未暴露问题;
  • 多字符字符串"aa"需要分配新内存块,触发_PyObject_Malloc时,线程因无有效解释器状态直接触发段错误(对应回溯中_PyInterpreterState_GET调用失败)。

解决方法

在OpenMP线程中调用Python API前,必须手动初始化线程状态并获取GIL,操作完成后释放GIL。使用PyGILState_Ensure()和PyGILState_Release()即可完成这一流程。

修改后的代码

#include <iostream>
#include "omp.h"
#include "Python.h"

int main()
{
    Py_Initialize();
    
    #pragma omp parallel
    {
        #pragma omp single
        {
            // 初始化线程状态并获取GIL
            PyGILState_STATE gstate = PyGILState_Ensure();
            
            std::cout << "One character:"<<std::endl;
            PyObject *nameobj1 = PyUnicode_FromString("a");
            std::cout << nameobj1 << std::endl;
            Py_DECREF(nameobj1);
            
            std::cout << "Two characters:"<<std::endl;
            PyObject *nameobj2 = PyUnicode_FromString("aa");
            std::cout << nameobj2 << std::endl;
            Py_DECREF(nameobj2);
            
            // 释放GIL并清理线程状态
            PyGILState_Release(gstate);
        }
    }
    
    Py_Finalize();
}

验证说明

  • 编译命令保持不变,Python 3.12环境下运行将不再触发段错误;
  • PyGILState_Ensure()会自动为非Python创建的线程初始化必要的解释器状态,并获取GIL;
  • PyGILState_Release()会释放GIL并清理线程状态,避免资源泄漏。

补充说明

  • 即使OpenMP仅在单个线程执行Python操作,该线程由OpenMP runtime创建,不属于Python线程池管理范畴,因此必须手动初始化状态;
  • Python 3.11及更早版本中,内存分配的状态检查未做严格限制,因此未触发该问题。

内容的提问来源于stack exchange,提问作者fffred

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 16:05:11