5

Cのスレッドで実行される組み込みのPythonプログラムがあります。

Pythonインタープリターがスレッドコンテキストを切り替えるとき(制御を別のスレッドに譲る)、特定の必要な操作を実行できるように通知を受け取りたいです。

それPy_AddPendingCallがまさに私が探しているもののようです。ただし、APIドキュメントはこの関数について非常に簡潔であり、どのようPy_AddPendingCallに使用されるかについて混乱しています。ドキュメントを読んだことから、私の理解は次のとおりです。

  • ワーカースレッドがPy_AddPendingCallハンドラー関数を呼び出して割り当てます。
  • Pythonインタープリターが実行されると、別のスレッドに制御を渡すたびにハンドラー関数が呼び出されます
  • ハンドラー自体はメインインタープリタースレッドで実行され、GILが取得されます

たとえば、使用方法を示すコードをグーグルでPy_AddPendingCall検索しましたが、何も見つかりません。私自身がそれを使おうとすると、うまくいきません。ハンドラーが呼び出されることはありません。

私のワーカースレッドコード:

#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>

const char* PYTHON_CODE = 
"while True:\n"
"   for i in range(0,10): print(i)\n"
"\n";

int handler(void* arg)
{
    printf("Pending Call invoked!\n");
    abort();
}

void* worker_thread(void*)
{
    PyGILState_STATE state = PyGILState_Ensure();
    int res = Py_AddPendingCall(&func, nullptr);
    cout << "Result: " << res << endl;
    PyRun_SimpleString(CODE);
    PyGILState_Release(state);

    return 0;
}

int main()
{
    Py_Initialize();
    PyEval_InitThreads();
    PyEval_ReleaseLock();

    pthread_t threads[4];
    for (int i = 0; i < 4; ++i)
        pthread_create(&threads[i], 0, worker_thread, 0);

    for (int i = 0; i < 4; ++i) pthread_join(threads[i], 0);

    Py_Finalize();
}

この例でworker_threadは、Cでpthreadワーカースレッドとして呼び出されます。このテストでは、4つのワーカースレッドを実行しているため、コンテキストの切り替えが発生するはずです。これは無限にループしますが、保留中の呼び出しハンドラーが呼び出されることはありません。

それで、誰かがどのように使用されることになっているのかを示す最小限の実用的な例を提供できますPy_AddPendingCallか?

4

1 に答える 1

6

保留中の呼び出しはメインスレッドでのみ実行され、メインスレッドはPythonコードを実行するときにのみ保留中の呼び出しを処理できます。したがって、保留中の呼び出しを処理するには、メインスレッドがインタープリターループを実行している必要があります。差出人Python/ceval.c

Py_MakePendingCalls(void)
{
    ...

    /* only service pending calls on main thread */
    if (main_thread && PyThread_get_thread_ident() != main_thread)
        return 0;

    ...
}

埋め込みシナリオでは、「メインスレッド」はスレッドが呼び出す方のスレッドPyEval_InitThreadsです(Pythonコードからスレッドを最初に開始したときにも自動的に呼び出されることに注意してください)。メインスレッドはにpthread_joinあるため、Pythonコードを実行しておらず、保留中の呼び出しをディスパッチしていません。

ハンドラーは、制御がメインスレッドに渡された場合にのみ実行されることにも注意してください。制御が1つのワーカーから別のワーカーに移る場合、ハンドラーは実行されません。したがって、Py_MakePendingCallsこのタスクに使用するのに適切なインターフェイスではない可能性があります。

于 2012-09-16T16:51:42.190 に答える