2012-02-04 3 views
16

私は、Cでユーザレベルのスレッドライブラリを作成するためのクラスに取り組んでいます。これを達成するために読んだことがある人がいるかと思います。私はどこから始めるべきかについては良い考えがありますが、ユーザレベルのスレッド上のリソースやC言語のいくつかの応用可能な側面が非常に貴重です。ユーザーレベルのスレッドパッケージの実装

スケジューラをどのように実装するのかは非常に不明です。私はC言語とそのより有用なライブラリ関数をよく理解していると仮定します。シンプルな協力スケジューラはswapcontextを使用してCで行うことができます

+4

「Cで」実行できないため、割り当てが少し難しいです。新しい実行コンテキストの作成を容易にし、それらの間で切り替えるには、最低限のアセンブリまたは同等のコンパイラ拡張が必要です。あるいは、あなた自身の完全な仮想マシンとCの実装を仮想マシン上で実行するように書くこともできますが、これはあなたのインストラクターが心に留めているものだとは思わないでしょう... –

+1

協調マルチタスク/スレッド化の場合、getcontext/makecontext /便利なsetcontext関数。 – MetallicPriest

+0

これは、レジスタコンテキストとスタックポインタの保存/復元を実装するために、何らかのアセンブラがなければ、これがどのように実行されるかわかりません。それはI/Oとそれを待つ方法を考えることさえありません。 –

答えて

8

私は宿題の割り当てのためにこれをやったことがありません。スレッドスイッチ機構はsetjmp/longjmpでした。これは、各スレッドのスタックにメモリを割り当ててから、jmp_buffの値を非常に慎重にマッサージすることで、次のスレッドのスタックにジャンプします。

も参照してくださいRuss Coxのかなり読みやすいlibtaskも参照してください。

OPのコメントに応じて編集:スレッドを切り替えるタイミングを決めるには、2つの主な方向があります:プリエンプティブ& cooperative。プリエンプティブモデルでは、実行フローを実行する中央ディスパッチャスレッドにジャンプさせるタイマー信号のようなものがあります。このディスパッチャスレッドは、次に実行するスレッドを選択します。協調モデルでは、スレッドは明示的に(、提供する関数yield()を呼び出すことによって)暗黙的に(たとえば、別のスレッドが保持するロックを要求して)相互に「降伏」します。

協力モデルの例、特に関数taskyield()の説明については、libtaskのAPIを参照してください。それは私が言及した明白な収穫です。暗黙の利回りを含むノンブロッキングI/O関数もあります。現在の「タスク」はI/Oが完了するまで保留されますが、他のタスクは実行の機会を得ます。

+0

これは私がスレッド切り替えを行うと想像していた方法です。私の知る限りの知識がないのは、スレッドがいつ制御を放棄して別のスレッドを実行できるかを判断する方法だと思います。スレッドが十分な時間を持っていると判断する方法 – SirensOfTitan

+0

@SirensOfTitan、私はあなたが今質問した内容をカバーするために私の答えを更新しました。 –

4

、swapcontextのmanページhereに例を見て、これはその出力です:

$ ./a.out 
main: swapcontext(&uctx_main, &uctx_func2) 
func2: started 
func2: swapcontext(&uctx_func2, &uctx_func1) 
func1: started 
func1: swapcontext(&uctx_func1, &uctx_func2) 
func2: returning 
func1: returning 
main: exiting 

だから、あなたはそれが非常になんとかです見ることができるように。

注:タイマーシグナルハンドラ内でコンテキストをスワップする場合は、自分自身に先制スケジューラがありますが、安全かどうかはわかりません。

編集:私はそれがシグナルハンドラ内でコンテキストを切り替えることが可能だということを示唆しては、sigactionのmanページでこれを見つけた:

SA_SIGINFOがsa_flagsに指定されている場合は、sa_sigactionの(代わりに はsa_handlerの) signumのシグナル処理関数を指定します。 この関数は、シグナル番号を第1引数として受け取り、第2引数としてsiginfo_tへのポインタ と、第3引数として ucontext_t(void *にキャスト)へのポインタを受け取ります。

+1

これは宿題の問題だと思います。 OPはそれが受け入れられるかどうかを確認する必要があります。おそらく、インストラクターは単にswapcontext()関数を単に使用するのではなく、その実装を探しています。 –

1

アップルのオープンソースの実装を調べることができます。スタックフレームの戻りアドレスの取得や任意のアドレスへのジャンプなど、Cで行うことができない特殊な処理が必要なため、コードの最大部分は実際にはアセンブリコードです。

ユーザランドスレッド(一般に「ファイバー」とも呼ばれます)は、一般に協調モデルを使用します。つまり、スレッドは十分な時間があると判断されるまで実行され、別のスレッドに渡されます。優先度キューを使用すると、最短時間実行されたタスクを実行するスケジューラを実装できます。 (スケジューラは実行中のタスクを追跡し、十分な時間が経過したと判断すると実行中のタスクが戻ります。スケジューラはタスクが実行された時間を更新し、実行時間が最も短いタスクに戻ります)。

関連する問題