25

在 Haskell 中编程时,我习惯于依赖 GHC 的forkIO可移植轻量级线程。

可以提供相同可扩展性和易用性的 C 等效库是什么?

具体来说,我需要至少以下两个函数的 C 等效项。

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

我假设对于我的应用程序,如果线程只打开阻塞操作而不是强制挂起就足够了,因为所有线程都非常频繁地阻塞网络 IO,并且我只使用splice系统调用来要求 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,因为即将执行 IO 的线程必须首先进行昂贵的测试以检查操作是否会阻塞,如果是,则将控制权移交给不同的线程。

我坚持我的立场,即“绿色线程”是一个早已过去的想法。这似乎也是 Austin Group(负责 POSIX)的立场,他们删除了ucontextPOSIX 2008 中的功能,并建议用 POSIX 线程(现在是强制性功能)替换。

于 2013-01-16T23:15:38.070 回答