単純な C++ クラスがあるとします。
class Widget
{
public:
Widget() :
x(1)
{ }
void sleep()
{
sleep(x);
}
private:
int x;
};
Widget::sleep
ブロックなので、Python が他のことをできるように GIL を解放したいので、次Widget::sleep
のような関数でラップしました。
static void pyWidgetSleep(Widget& self)
{
PyThreadState* state = PyEval_SaveThread();
self.sleep();
PyEval_RestoreThread(state);
}
完全を期すために、バインディング コードは次のようになります。
BOOST_PYTHON_MODULE(libnative)
{
boost::python::class_<Widget>("Widget")
.def("sleep", &pyWidgetSleep);
}
次のような単純な Python スクリプトがあります。
import libnative
import threading
class C:
def __init__(self):
self.x = libnative.Widget()
self.sleeping = False
def foo(self):
self.sleeping = True
self.x.sleep()
c = C()
t = threading.Thread(target=c.foo)
t.start()
while not c.sleeping:
pass
del c.x
エクスプレッションのすべての参加者は、エクスプレッションの期間中、参照カウントがインクリメントされますか? c.x
で使用される場合の唯一の指示対象C.foo
はc
であり、後の行でt.start()
都合よく削除されます。pyWidgetSleep
GIL を解放してからdel c.x
、インスタンスへの最後の参照をデクリメントし、Widget
未定義の動作を引き起こす可能性があります。
私のマシンではこのブレークを作成できません。これは、期待どおりに動作することを示す良い兆候のようですが、参照カウントはこの程度明確に文書化されていません (または、少なくとも、できる.見つからないようです)。CPython の関連部分は のように見えます。これは、関数呼び出しに関係するすべての引数にPyEval_EvalCodeEx
適用されるように見えますが、私はそれについて完全にオフになっている可能性があります。Py_INCREF