4

課題の一環として、pthreads のようなユーザー レベルのスレッド ライブラリを作成しようとしています。

スレッド間のコンテキスト切り替えを処理するために、「swapcontext」関数を使用しています。それを使用する前に、「makecontext」関数を使用してコンテキストを作成する必要があります。'makecontext' は、戻り値の型voidと引数の型を持つ関数ポインターを想定しています(void)

一方、スレッド関数は型でなければなりませんvoid* thread_func (void*)

型キャストを行う方法はありますか?または、ユーザーレベルでコンテキスト切り替えを行う他の方法はありますか?

4

3 に答える 3

7

関数のアドレスを別のプロトタイプにキャストし、結果のポインターを介して呼び出すことにより、互換性のないプロトタイプで関数を呼び出すことは違法です。

void *my_callback(void *arg) { ... }

void (*broken)(void *) = (void (*)(void *)) my_callback;
broken(some_arg);   // incorrect, my_callback returns a `void *`

あなたができることは、その戻り値makecontextを呼び出して無視するあなた自身のコールバックに渡すことです。thread_func別の関数を呼び出すためだけに機能する小さな関数は、トランポリンと呼ばれることもあります。

/* return type is compatible with the prototype of the callback received
   by makecontext; simply calls the real callback */
static void trampoline(int cb, int arg)
{
  void *(*real_cb)(void *) = (void *(*)(void *)) cb;
  void *real_arg = arg;
  real_cb(real_arg);
}

int my_pthread_create(void *(*cb)(void *), void *arg)
{
  ucontext_t *ucp;
  ...
  /* For brevity treating `void *` as the same size as `int` -
     DO NOT USE AS-IS.
     makecontext exposes an annoyingly inconvenient API that only
     accepts int arguments; correct code would deconstruct each
     pointer into two ints (on architectures where pointer is
     larger than int) and reconstruct them in the trampoline. */
  makecontext(ucp, trampoline, 2, (int) cb, (int) arg);
  ...
}

ボーナスポイントについては、トランポリンを変更して、コールバック関数によって返された値をスタックに格納しvoid *、同等の値をpthread_join()取得することができます。

于 2013-01-25T21:03:42.817 に答える
4

原則として、どのタイプのポインターも他の種類のポインターにいつでもキャストできますが、関数ポインターの場合は、に対して強くお勧めします。

thread_funcミスキャストの後に呼び出された場合は提供されないスタック上の引数を期待します。さらに悪いことに、thread_func本来あるべきではない場所に戻り値を書き込むため、スタックが破損します。

解決策は、呼び出しを適切なタイプの独自の関数でラップすることです。

于 2013-01-25T21:04:51.213 に答える
0

変数と同じように関数ポインタを型キャストできます。構文はもっと厄介ですが、それは確かに可能です(それが良い考えであるかどうかは完全に別の議論です)。

ただし、この場合、それはおそらくあなたがやりたいことではありません。のマニュアルページからswapcontext

makecontext()を呼び出す前に、呼び出し元はこのコンテキストに新しいスタックを割り当て、そのアドレスをucp->uc_stackに割り当てる必要があります。

スレッド関数は引数を取ります。作成したスタックを介して、その引数を新しいコンテキストに渡します。渡すmakecontext()関数は、スタックから値を取得し、それを引数としてスレッド関数に渡すラッパー関数にすることができます。型キャストだけでは、引数のデータを新しいコンテキストの関数に取得する方法は提供されません。

于 2013-01-25T21:03:50.720 に答える