25

私はforkIOHaskell でプログラミングするとき、移植可能な軽量スレッドを GHC に依存することに慣れています。

同じスケーラビリティと使いやすさを提供できる C の同等のライブラリは何ですか?

具体的には、少なくとも次の 2 つの関数の C 版が必要です。

forkIO     :: IO () -> IO ThreadId
killThread ::             ThreadId -> IO ()

splice私のアプリケーションでは、すべてのスレッドがネットワーク IO のために非常に頻繁にブロックされ、システム コールを使用して Linux カーネルにソケット間でデータをプッシュするように要求するだけなので、スレッドが強制的に中断されるのではなく、ブロッキング操作をオンにするだけで十分だと思います。


アップデート

この論文には、比較する図と表があります

Protothreads に有利な結果が得られました。私は何も使用したことがなく、他のライブラリもあるかもしれないので、そのようなライブラリを使用/開発したことがある人からの連絡をお待ちしています.

4

3 に答える 3

10

libMill はおそらくあなたが探しているものです: http://libmill.org/

Go-Lang チャネル スタイルでユーザー レベルのスレッドを実装します。

また、ZeroMQ http://250bpm.com/の作成者である非常にスマートな Martin Sústrik によって開発されています。だからいいに違いない☺</p>

于 2016-01-09T16:16:33.810 に答える
4

次のコードや例についてのコメントはもうありません-これはプリプロセッサマクロとして実装されたポータブル(疑似)スレッドライブラリです

     typedef struct
     {
     unsigned int magic;
     unsigned short ctx;
     unsigned char is_destroyed;
     }
     _run;

     typedef struct
     {
     unsigned int magic;
     unsigned int cnt;
     }
     _sem;


     #define aa_RUNNER_WAITING             0
     #define aa_RUNNER_YIELDED             1
     #define aa_RUNNER_EXITED              2
     #define aa_RUNNER_ENDED               3

     #define aaRunnerCreate(rp)            (rp)->magic='runr'; (rp)->ctx=0; (rp)->is_destroyed=NO
     #define aaRunnerDestroy(rp)           (rp)->is_destroyed=YES

     #define aaRunnerThread(args)          C args
     #define aaRunnerBegin(rp)             { C yflag=YES; if(yflag) {}  switch((rp)->ctx) { case 0:
     #define aaRunnerEnd(rp)               } yflag=NO; if(yflag) {}  aaRunnerCreate(rp); return aa_RUNNER_ENDED; }

     #define aaRunnerWaitUntil(rp,condx)   do  { (rp)->ctx=__LINE__; case __LINE__: if(!(condx))  { return aa_RUNNER_WAITING;  }  } while(0)
     #define aaRunnerWaitWhile(rp,condi)   aaRunnerWaitUntil((rp),!(condi))
     #define aaRunnerWaitThread(rp,thr)    aaRunnerWaitWhile((rp),aaRunnerSchedule(thr))
     #define aaRunnerWaitSpawn(rp,chl,thr) do { aaRunnerCreate((chl));  aaRunnerWaitThread((rp),(thr)); } while(0)

     #define aaRunnerRestart(rp)           do { aaRunnerCreate(rp); return aa_RUNNER_WAITING; } while(0)
     #define aaRunnerExit(rp)              do { aaRunnerCreate(rp); (rp)->magic=0; return aa_RUNNER_EXITED;  } while(0)

     #define aaRunnerSchedule(f)           ((f)<aa_RUNNER_EXITED)
     #define aaRunnerYield(rp)             do { yflag=NO; (rp)->ctx=__LINE__; case __LINE__: if(!yflag||!((rp)->is_destroyed))  { return aa_RUNNER_YIELDED;  }  } while(0)
     #define aaRunnerYieldUntil(rp,condi)  do { yflag=NO; (rp)->ctx=__LINE__; case __LINE__: if(!yflag||!(condi)) { return aa_RUNNER_YIELDED;   }   } while(0)

     #define aaRunnerSemInit(sp,c)         (sp)->magic='runs'; (sp)->cnt=c
     #define aaRunnerSemWait(rp,sp)        do { aaRunnerWaitUntil(rp,(sp)->cnt>0); --(sp)->cnt;  } while(0)
     #define aaRunnerSemSignal(rp,sp)      ++(sp)->cnt
于 2013-01-31T00:59:58.040 に答える
-16

POSIXスレッドを使用します。これらは、「グリーンスレッド」という意味ではなく、軽量で効率的であるという意味で、最新の実装では「グリーン」です。プレーンCまたはPOSIXマイナススレッドの上に独自のスレッドをロールするポータブルな方法はありません。OPが述べたように、移植性のない方法でグリーンスレッド/コルーチンを実装しているライブラリがいくつかあります(多くの場合、移植性を主張しているにもかかわらず)。

最もポータブルなアプローチはmakecontext/を使用することですswapcontextが、残念ながら、「スレッド」間の各スイッチでシグナルマスクを保存/復元するためにシステムコールを実行する必要があるため、これはうまく機能しません。これにより、「グリーン」スレッド間の切り替えは、「実際の」POSIXスレッド実装でのカーネルレベルスレッド間のコンテキスト切り替えよりもコストがかかり、基本的に「グリーンスレッド」の主張されている利点が無効になります。

シグナルマスクを気にしない非移植性のアプローチでは、マシン固有のasmを使用して、完全にユーザースペースでコンテキストスイッチを実行でき、理論的にはカーネルレベルのスレッドよりもパフォーマンスが向上しますが、パフォーマンスはすぐに再びウィンドウから飛び出します。 IOを導入しようとしているスレッドは、最初に操作がブロックされるかどうかを確認するために高価なテストを実行する必要があるため、ブロックされる場合は、制御を別のスレッドに引き渡します。

私は、「グリーンスレッド」は昔の考えであるという立場を維持しています。ucontextこれは、POSIX 2008で機能を削除し、POSIXスレッド(現在は必須機能)への置き換えを推奨したAustin Group(POSIXを担当)の立場でもあるようです。

于 2013-01-16T23:15:38.070 に答える