2012-08-29 93 views
5

我有一個簡單的測試案例在這裏:痛飲崩潰的Python

%module test 
%{ 

static char* MyExceptionName = "_test.MyException"; 
static PyObject* MyException = NULL; 

%} 

%inline %{ 

static PyObject* Foo() 
{ 
    PyErr_SetNone(MyException); 
    return NULL; 
} 

%} 

%init 
{ 
    MyException = PyErr_NewException(MyExceptionName, NULL, NULL); 
} 

下面是setup.py腳本:

from distutils.core import setup, Extension 
setup(name="test", version="1.0", 
    ext_modules = [Extension("_test", ["test_wrap.c"])]) 

當我建立並測試它如下,我得到:

swig -python -threads test.i 
python_d -c "import test; test.Foo()" 
Fatal Python error: PyThreadState_Get: no current thread 

我得到的回溯是

python27_d.dll!Py_FatalError(const char * msg=0x000000001e355a00) Line 1677 C 
python27_d.dll!PyThreadState_Get() Line 330 C 
python27_d.dll!PyErr_Restore(_object * type=0x00000000020d50b8, _object * value=0x0000000000000000, _object * traceback=0x0000000000000000) Line 27 + 0x5 bytes C 
python27_d.dll!PyErr_SetObject(_object * exception=0x00000000020d50b8, _object * value=0x0000000000000000) Line 58 C 
python27_d.dll!PyErr_SetNone(_object * exception=0x00000000020d50b8) Line 64 C 
_test_d.pyd!Foo() Line 2976 C 

環境:

  • Win 7的64位,
  • 的Python 2.7.3(默認情況下,2012年8月15日,十八時18分52秒)[MSC v.1500 64位(AMD64)]在Win32
  • 痛飲2.0.7

回答

3

的原因的錯誤,因爲它原來是因爲當-threads通過

swig -threads -python test.i 
啓用

我們得到這樣的(多餘的代碼已經被刪節):

PyObject *_wrap_Foo(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { 
    PyObject *resultobj = 0; 
    PyObject *result = 0 ; 

    if (!PyArg_ParseTuple(args,(char *)":Foo")) SWIG_fail; 
    { 
    SWIG_PYTHON_THREAD_BEGIN_ALLOW; 
    result = (PyObject *)Foo(); 
    SWIG_PYTHON_THREAD_END_ALLOW; 
    } 
    resultobj = result; 
    return resultobj; 
fail: 
    return NULL; 
} 

static PyObject* Foo() 
{ 
    PyErr_SetNone(MyException); 
    return NULL; 
} 

看,當富()被調用時,全局解釋鎖已被釋放。 Foo()不應再進行任何Python API調用。

解決方案是使用SWIG_Python_SetErrorObj,它在調用Python C API之前抓取全局解釋器鎖。

static PyObject* Foo() 
{ 
    SWIG_Python_SetErrorObj(MyException, Py_None); 
    return NULL; 
} 

另一種方法是使用SWIG_PYTHON_THREAD_BEGIN_BLOCK;和SWIG_PYTHON_THREAD_END_BLOCK;

static PyObject* Foo() 
{ 
    SWIG_PYTHON_THREAD_BEGIN_BLOCK; 

    PyErr_SetNone(MyException); 

    SWIG_PYTHON_THREAD_END_BLOCK; 
    return NULL; 
}