Почему PyGILState_Release выдает фатальные ошибки Python

ANSWERED

Хорошо, я решил эту проблему. Все дело в том, как вы инициализируете состояние потока. Вам вообще не нужно использовать ReleaseLock. добавьте вызов InitThreads в определение вашего модуля:

BOOST_PYTHON_MODULE(ModuleName)
{
    PyEval_InitThreads();

    ...
}

Хорошо, я пытался диагностировать эту проблему в течение нескольких часов и изучал то, что кажется, каждый пример в Интернете. Теперь устал, поэтому я могу упустить что-то очевидное, но вот что происходит :

Я оборачиваю библиотеку в boost python. Я запускаю сценарий python, который импортирует библиотеку, создает некоторые объекты, а затем получает обратные вызовы от c ++, который обращается обратно в python. Прежде чем я вызываю вызов любых функций python, я пытаюсь выполнить получить глобальную блокировку интерпретатора Вот пример кода:

class ScopedGILRelease
{
public:
   inline ScopedGILRelease()
   {
      d_gstate = PyGILState_Ensure();
   }

   inline ~ScopedGILRelease()
   {
      PyGILState_Release(d_gstate);
   }

private:
   PyGILState_STATE  d_gstate;
};

class PyTarget : public DingoClient::ClientRequest::Target, public wrapper<DingoClient::ClientRequest::Target>
{
  public:
    PyTarget(PyObject* self_) : self(self_) {}
    ~PyTarget() {
      ScopedGILRelease gil_lock;
    }
    PyObject* self;

    void onData(const boost::shared_ptr<Datum>::P & data, const void * closure)
    {
       ScopedGILRelease gil_lock;
       // invoke call_method to python 
    }

    ...
}

Метод onData объекта Target вызывается библиотекой в ​​качестве обратного вызова.В python мы наследуем от PyTarget и реализуем другой метод. Затем мы используем call_method <> для вызова этого метода. gil_lock получает блокировку и через RIAA гарантирует, что полученное состояние потока всегда является единственным выпуском и что оно фактически всегда освобождается при выходе из области видимости.

Однако, когда я запускаю это в сценарии, который пытается получить большое количество обратных вызовов для этой функции, всегда происходит сбой. Скрипт выглядит примерно так:

# Initialize the library and setup callbacks
...

# Wait until user breaks
while 1:
  pass

Кроме того, скрипт python всегда создает объект, который запускается:

PyEval_InitThreads();
PyEval_ReleaseLock();

перед получением каких-либо обратных вызовов.

Я сократил код до такой степени, что я даже не вызываю python в onData, я просто получаю блокировку. При выпуске он всегда дает сбой либо:

Fatal Python error: ceval: tstate mix-up
Fatal Python error: This thread state must be current when releasing

, либо

Fatal Python error: ceval: orphan tstate
Fatal Python error: This thread state must be current when releasing

Это, по-видимому, случайное. Я сумасшедший, потому что мне кажется, что я правильно использую блокировку GIL, но, похоже, она вообще не работает.

Другие примечания: Только один поток когда-либо вызывает метод onData этого целевого объекта.

Когда я сплю в цикле while в вызывающем модуле python с time.sleep (), кажется, что скрипт может работать дольше, но в конечном итоге скрипт выйдет из строя с аналогичными проблемами. Количество времени, которое он длится, пропорционально количеству time.sleep (то есть time.sleep (10) работает дольше, чем time.sleep (0,01). Это заставляет меня задуматься о том, как скрипт повторно получает GIL без моего разрешения .

PyGILState_Release и PyGILState_Ensure вызываются нигде в моем коде, нигде еще не следует вызывать python.

Обновление

Я прочитал еще один вопрос, в котором предлагается импортировать потоки в модуль в качестве альтернативы выполнению

PyEval_InitThreads();
PyEval_ReleaseLock();

. Однако он не работает, когда я импортирую потоки перед своим модулем и удаляю две приведенные выше строки из моя оболочка для ускорения python.

8
задан Daniel DeSousa 9 December 2011 в 21:41
поделиться