10

C (または C++) スレッドから Python コードを呼び出すときに、スレッドセーフをどのように確保できるかについて、私は非常に混乱しています。

Pythonのドキュメントでは、そうするための通常のイディオムは次のようになっているようです。

PyGILState_STATE gstate;
gstate = PyGILState_Ensure();

/* Perform Python actions here. */
result = CallSomeFunction();
/* evaluate result or handle exception */

/* Release the thread. No Python API allowed beyond this point. */
PyGILState_Release(gstate);

実際、このスタックオーバーフローの回答は、それを裏付けているようです。しかし、コメント投稿者 (非常に評判が高い) は別のことを言っています。コメンターは、PyEval_RestoreThread()/を使用する必要があると言いますPyEval_SaveThread()

ドキュメントはこれを確認しているようです:

PyThreadState* PyEval_SaveThread()

Release the global interpreter lock (if it has been created and 
thread support is enabled) and reset the thread state to NULL, 
returning the previous thread state (which is not NULL). If the lock 
has been created, the current thread must have acquired it. (This 
function is available even when thread support is disabled at compile 
time.)

void PyEval_RestoreThread(PyThreadState *tstate)

Acquire the global interpreter lock (if it has been created and thread 
support is enabled) and set the thread state to tstate, which must not 
be NULL. If the lock has been created, the current thread must not have 
acquired it, otherwise deadlock ensues. (This function is available even 
when thread support is disabled at compile time.)

ドキュメントがこれを説明する方法は、PyEval_RestoreThread()/PyEval_SaveThread()が基本的にミューテックスのロック/ロック解除のイディオムであるようです。したがって、C から Python コードを呼び出す前に、まず GIL をロックしてからロックを解除する必要があります。

それで、それはどれですか?C から Python コードを呼び出す場合、次を使用する必要があります。

PyGILState_Ensure()/PyGILState_Release()

また

PyEval_RestoreThread/PyEval_SaveThread?


そして、実際の違いは何ですか?

4

1 に答える 1

6

PyEval_RestoreThreadまず、 /を呼び出すことはほとんどありませんPyEval_SaveThread。代わりに、ラッパー マクロPy_BEGIN_ALLOW_THREADS/を呼び出しますPy_END_ALLOW_THREADSドキュメントはそれらのマクロ用に書かれているため、見つけることができませんでした。

いずれにしても、スレッド関数/マクロを使用して GIL を取得することはありません。それらを使用して、GIL を取得したときに GIL を一時的に解放します。

それで、なぜあなたはこれをしたいのですか?まあ、単純なケースではそうではありません。Ensure/だけが必要ですRelease。しかし、後でまで Python スレッドの状態を保持する必要がある場合がありますが、GIL を保持する必要はありません (または、GIL を保持する必要がないことを明示的に示して、他のスレッドが進行できるようにする必要があります)。ドキュメントで説明されているように、これの最も一般的な理由は、ファイル I/O または大規模な CPU バウンド計算を行っていることです。

最後に、マクロの代わりに関数を呼び出したい場合はありますか? はい、スタッシュされた PyThreadState にアクセスしたい場合。それが必要な理由が思い浮かばない場合は、おそらくそれがありません。

于 2012-09-14T22:24:43.320 に答える