То, с чем вы сталкиваетесь, это глобальная блокировка интерпретатора python.GIL позволяет запускать только один поток в интерпретаторе python.
Одним из преимуществ Boost.Python является то, что вы можете освободить GIL, выполнить C ++ и затем вернуть его, когда закончите.Это также ответственность, однако.Обычно Python выпускает GIL через равные промежутки времени, чтобы другие потоки могли работать.Если вы находитесь на C ++, это ваша работа.Если вы удерживаете цифры GIL в течение 2 часов, удерживая GIL, вы замораживаете весь переводчик.
Это можно легко исправить с помощью небольшого обратного RAII:
class releaseGIL{
public:
inline releaseGIL(){
save_state = PyEval_SaveThread();
}
inline ~releaseGIL(){
PyEval_RestoreThread(save_state);
}
private:
PyThreadState *save_state;
};
Теперь вы можете изменить свой код следующим образом:
class Foo{
public:
Foo(){}
void run(){
{
releaseGIL unlock = releaseGIL();
int seconds = 2;
clock_t endwait;
endwait = clock () + seconds * CLOCKS_PER_SEC ;
while (clock() < endwait) {}
}
}
};
Это ОЧЕНЬ важнообратите внимание, что вы НЕ ДОЛЖНЫ касаться кода Python, данных Python или вызывать интерпретатор, не удерживая GIL.Это приведет к сбою вашего переводчика.
Также возможно пойти другим путем.Поток, в настоящее время не содержащий GIL, может получить его и сделать вызовы в python.Это может быть поток, выпустивший GIL ранее, или поток, начатый в c ++ и никогда не имевший GIL.Вот класс RAII для этого:
class AcquireGIL
{
public:
inline AcquireGIL(){
state = PyGILState_Ensure();
}
inline ~AcquireGIL(){
PyGILState_Release(state);
}
private:
PyGILState_STATE state;
};
Использование оставлено в качестве упражнения для студента.
Дополнительные примечания (я всегда забываю об этом упоминать):
Если вы собираетесь возиться с GIL в c ++, определение вашего модуля должно начинаться с этого кода:
BOOST_PYTHON_MODULE(ModuleName)
{
PyEval_InitThreads();
...
}