2012-03-02 13 views
3

私を助けてください。
私は別のC++スレッドからpythonスクリプトを呼び出そうとしていて、問題に直面しています。C++スレッドからpythonスクリプトを呼び出すGIL

メイン:

Py_Initialize();  
PyEval_InitThreads(); 
PyThreadState *mainThreadState = PyThreadState_Get(); 
PyEval_ReleaseLock(); 
PyInterpreterState *mainInterpreterState = mainThreadState->interp; 
... 
//creating threads with myThreadState per thread 
    PyEval_AcquireLock(); 
    PyThreadState *myThreadState = PyThreadState_New(mainInterpreterState); 
    PyEval_ReleaseLock(); 
//running threads 
... 
PyEval_RestoreThread(mainThreadState); 
Py_Finalize(); 

実行スレッドオブジェクト()関数:

PyEval_AcquireLock(); 
PyThreadState_Swap(m_threadState); 
... 
script = "f = open('file_for_this_thread','w')\n" 
     "print f\n" 
     "f.write('111')\n"      
     "print f.fileno()\n" 
PyRun_SimpleString(script); 
... 
PyThreadState_Swap(NULL); 
PyEval_ReleaseLock(); 

'プリントF' はそれぞれのファイル の正しいファイル情報を表示します。しかし、何かが間違っている、2番目の「プリントF理由'異なるスレッドに同じものを出力し、出力がある場合はそのスレッドごとに異なるファイルの代わりに1つのファイルに移動する
f.writeの代わりにtime.sleep(1)を挿入するとファイルハンドラが等しくなる、あまりにも 何がクラッシュしていない..

も、PyGILState_Ensure/PyGILState_Releaseを使用して、同じ効果
主を試みた:

Py_Initialize(); 
PyEval_InitThreads(); 
PyThreadState* mainThreadState = PyEval_SaveThread(); 
... 
//creating and running threads 
... 
PyEval_RestoreThread(mainThreadState); 
Py_Finalize(); 

ロッカー:スレッドオブジェクトに

TPyScriptThreadLocker: 
    PyGILState_STATE m_state; 
public: 
    TPyScriptThreadLocker(): m_state(PyGILState_Ensure() {} 
    ~TPyScriptThreadLocker() { PyGILState_Release(m_state); } 

ラン()関数:

TPyScriptThreadLocker lock; 
... 
script = "f = open('file_for_this_thread','w')\n" 
     "print f.fileno()\n" 
     "f.write('111')\n"      
     "print f.fileno()\n" 
PyRun_SimpleString(script); 

I kno Pythonでそのマルチスレッドは、ほとんどの場合には良いアイデアではありませんが、今、私はこのコードと間違っているかを知りたいのw ...

のPython 2.7
http://www.linuxjournal.com/article/3641?page=0,2

ソースからの情報:http://files.mail.ru/9D4TEF ペーストビン:http://pastebin.com/DfFT9KN3

+1

申し訳ありませんが、これは愚かな質問のように聞こえるが、どのようにファイル名を定義しますか?あなたのコードでは '' file_for_this_thread''とだけ言います。そのファイル名はどのくらい正確に決まっていますか? – jogojapan

+0

そのショートカットですが、実際にはQString( "d:\\%1")のようなスレッドごとに一意のファイルパスがあります。最初のf.writeは正常に動作し、2番目のものは正常に動作しません.f.fileno出力の前にtime.sleep(1)を挿入すると同じことが起こります。つまり、2つの異なるスレッドが同時に(同時に) –

+0

問題を示す最小限の例はありますか? – James

答えて

1

私のコメントで分析として、問題は、あなたのコード内のすべてのスレッドがPythonインタプリタの同じインスタンスを使用することに起因作成し、ここでは初期化されます。

Py_Initialize();  

最初のスレッドは、ここで定義されたスクリプトを実行すると:

script = "f = open('file_for_this_thread','w')\n" 
     "print f.fileno()\n" 
     "f.write('111')\n"      
     "print f.fileno()\n" 

これはグローバルPythonの変数fを割り当てるにはPythonインタプリタの原因を。その直後に別のスレッドは、同じグローバル変数を再定義します。これは最初のprint f.fileno()の時点では起こっていないかもしれませんが、明らかに2番目のものの前に起こります。

解決策は、グローバル変数がスレッド間で共有されないようにすることです(または、スレッドごとにPythonインタープリタの別のインスタンスを使用し、大きなメモリを追加する必要があります)。

コード内の唯一のグローバルPython変数はfなので、すべてのスレッドで異なる名前のfを使用すれば十分です。あなたのコードはより複雑になるにつれ、Pythonの関数を定義し、fを使用する方がよいでしょう(とあなたが必要とする任意の他の変数)のローカル変数として:

PyRun_SimpleString(
    "def myfunc(thread_no):\n" 
    " f = open('file_for_thread_%d' % thread_no,'w')\n" 
    " print f.fileno()\n" 
    " f.write('111')\n"    
    " print f.fileno()\n" 
); 

は、上記の一度だけをを適用しなければならないであろういずれかのスレッドがを実行する前にはです。各スレッドで

、あなたは、単に

PyRun_SimpleString(QString("myfunc(%d)\n",current_thread_no)); 

すなわちを行うだろうスレッドはPython関数のみを呼び出し、fはローカル変数になります。

+0

シンプルなテストプロジェクトを作ろうとしましたが、シンプルさのために問題が発生しました:)ありがとう。 –

関連する問題