2010-11-11 46 views
3

以下是在多線程程序使用Python解釋的例子:在同步多線程程序嵌入式Python

#include <python.h> 
#include <boost/thread.hpp> 

void f(const char* code) 
{ 
    static volatile auto counter = 0; 
    for(; counter < 20; ++counter) 
    { 
     auto state = PyGILState_Ensure(); 
     PyRun_SimpleString(code); 
     PyGILState_Release(state); 

     boost::this_thread::yield(); 
    } 
} 

int main() 
{ 
    PyEval_InitThreads(); 
    Py_Initialize(); 
    PyRun_SimpleString("x = 0\n"); 
    auto mainstate = PyEval_SaveThread(); 

    auto thread1 = boost::thread(f, "print('thread #1, x =', x)\nx += 1\n"); 
    auto thread2 = boost::thread(f, "print('thread #2, x =', x)\nx += 1\n"); 
    thread1.join(); 
    thread2.join(); 

    PyEval_RestoreThread(mainstate); 
    Py_Finalize(); 
} 

它看起來很好,但它是不同步的。 Python解釋器在PyRun_SimpleString期間多次釋放並重新獲取GIL(請參閱docs, p.#2)。

我們可以使用我們自己的同步對象來序列化PyRun_SimpleString調用,但這是一種錯誤的方式。

Python有自己的同步模塊 - _threadthreading。但他們並沒有在此代碼的工作:

Py_Initialize(); 
PyRun_SimpleString(R"(
import _thread 
sync = _thread.allocate_lock() 

x = 0 
)"); 

auto mainstate = PyEval_SaveThread(); 

auto thread1 = boost::thread(f, R"(
with sync: 
    print('thread #1, x =', x) 
    x += 1 
)"); 
  • 則產生了一個錯誤File "<string>", line 3, in <module> NameError: name '_[1]' is not defined和死鎖。

如何同步嵌入式python代碼最有效的方式?

+1

你會期望什麼輸出? – 2010-11-11 10:04:20

+0

@Sven Marnach:謝謝你的評論,更新了這個問題。 – Abyx 2010-11-11 19:59:33

回答

2

with語句在Python 3.1 issue,但它是固定在Python 3.2和Python 2.7。

所以正確的解決方案是使用threading模塊進行同步。

爲避免出現此類問題,您不應使用在globals字典中使用臨時變量的多線程代碼,也不要爲每個線程使用不同的全局變量字典。

4

當CPython調用可能會阻塞(或重新輸入Python)的函數時,它在調用函數之前釋放全局解釋器鎖,然後在函數返回後重新獲取鎖。在您的代碼中,您調用內置的print函數,該函數會釋放解釋器鎖並運行其他線程(請參閱stringobject.c中的string_print)。

因此,您需要您自己的鎖:全局解釋器鎖不適合確保執行I/O的Python代碼的序列化。

由於您使用的是Boost線程框架,因此您可能會發現使用其中一個Boost thread synchronization primitives(例如, boost::interprocess::interprocess_mutex

[編輯:我原來的答案是錯誤的,因爲通過Abyx指出。]

+0

不,這隻意味着PyGILState_Ensure將會阻塞,直到GIL被釋放。看到它的源代碼,它調用PyThread_acquire_lock。 – Abyx 2010-11-11 11:05:59

+0

你說得對,它調用'PyEval_RestoreThread'。讓我再嘗試一次。 – 2010-11-11 11:31:42