5

ここに最も単純なテストケースがあります:

%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:18:52)[MSC v.1500 64ビット(AMD64)] on win32
  • スウィッグ2.0.7
4

1 に答える 1

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()が呼び出されたとき、グローバルインタープリターロックはすでに解放されています。Foo()はPythonAPI呼び出しを行わないようにする必要があります。

解決策は、PythonCAPIを呼び出す前にグローバルインタープリターロックを取得するSWIG_Python_SetErrorObjを使用することです。

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

もう1つの方法は、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;
}
于 2012-08-29T14:27:13.937 に答える