2011-03-01 39 views
3

我正在封裝一個C函數,它執行阻塞操作(select),然後處理傳入的消息。我的理解是,當一個C函數是要阻止,正確的方法來調用它同時允許其他線程運行是:是否有可能在C函數之前釋放GIL並阻止並可能回調到Python?

Py_BEGIN_ALLOW_THREADS             
blocking_function(); 
Py_END_ALLOW_THREADS 

然而,碰巧這個功能作爲一個參數的回調指針。調用此回調函數處理由C函數預處理的傳入消息。我已經成功地將此回調包裝在一個調用PyEval_CallObject()的函數中,允許我將它傳遞給Python回調函數。

現在我加入線程支持,我不知道是否有可能同時向:

  • 調用這個阻塞操作之前釋放GIL。
  • 讓這個阻塞操作安全地回調到python解釋器中。

這會導致問題嗎?如果是這樣,是否有解決方法?

謝謝。

+0

看來正確的方法可能是重新捕獲我的處理程序中調用「PyEval_CallObject」的GIL。但是,這意味着傳遞保存的'PyThreadState',這看起來有點棘手! – Steve 2011-03-01 19:11:35

回答

7

幾個月前我使用了這些API函數,我的回憶有點朦朧,但我相信這段代碼會解決你的問題。我假定版本2.x(3.x的可以是不同的):

PyGILState_STATE gstate; 
gstate = PyGILState_Ensure(); 

/* Make your call to PyEval_CallObject() here (and any other PY API calls). */ 

PyGILState_Release(gstate); 

(以上是從採取:Python C/API docs

這基本上是Py_BEGIN_ALLOW_THREADS/Py_END_ALLOW_THREADS 宏的倒數。在這些內部,你釋放GIL,但在PyGILState函數中獲得GIL。

+0

PyGILState_Ensure/Release API也適用於Python 3。 – ncoghlan 2011-03-02 02:53:54

1

如果我使用全局存儲PyEval_SaveThread的結果,並在回調中使用它,請致電PyEval_RestoreThread。我只需要弄清楚如何通過回調的上下文指針更乾淨地將其傳遞給我的代碼中的回調函數。

+0

現在PyGILState API已經可用了,使用這些API是一個很好的主意(如dappawit的回答中所述)。 – ncoghlan 2011-03-02 02:52:11

相關問題