Какие библиотеки зеленых streamов доступны для C, которые могут соответствовать производительности и простоте использования зеленых streamов Haskell?

Я хорошо привык полагаться на forkIO GHC для портативных легких streamов при программировании в Haskell.

Что такое эквивалентные библиотеки для C, которые могут обеспечить такую ​​же масштабируемость и простоту использования?

В частности, мне нужны С-эквиваленты, по крайней мере, следующих двух функций.

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

Я полагаю, что для моего приложения было бы достаточно, если бы streamи только включали блокирующие операции, а не были принудительно приостановлены, потому что все streamи часто очень часто блокируются для сетевого ввода-вывода, и я использую только системный вызов для splice чтобы попросить kernel ​​Linux нажимать данные между сокетами ,


Обновить

В этой статье приведены цифры и таблицы, сравнивающие

  • GNU Pth
  • Protothreads
  • Посылка PM2

с результатами, благоприятствующими Protothreads. Поскольку я не использовал их, и могут быть и другие библиотеки, мне бы очень хотелось услышать от тех, кто использовал / разработал такие библиотеки.

libMill – это то, что вы ищете: http://libmill.org/

Он реализует streamи уровня пользователя в стиле канала Go-Lang.

И он разрабатывается супер-умным Мартином Сустриком, создателем ZeroMQ http://250bpm.com/ . Так что это должно быть хорошо ☺

У меня больше нет комментариев для следующего кода, ни примеров – это портативная (псевдо) библиотека streamов, реализованная как macros предварительного процессора

  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)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 

Используйте streamи POSIX. Они «зеленые» в любой современной реализации, а не в смысле «зеленых нитей», но в смысле легкого и эффективного. Нет никакого переносного способа перевернуть ваши собственные streamи поверх простых C или POSIX минус streamов. Как упоминалось в OP, есть несколько библиотек, реализующих «зеленые streamи» / совместные подпрограммы в непереносимом режиме (часто, несмотря на требование мобильности).

Самый близкий к портативному подходу использует makecontext / swapcontext , и, к сожалению, это не может работать хорошо, потому что он должен делать системные вызовы для сохранения / восстановления маски сигнала на каждом коммутаторе между «streamами». Это делает переход между «зелеными» streamами дороже, чем переключение контекста между streamами уровня ядра в «реальной» реализации streamов POSIX и в основном отрицает любое заявленное преимущество «зеленых streamов».

Не переносимые подходы, которые не заботятся о сигнальной маске, могут использовать специфический для машины asm, чтобы полностью переключаться на контекст в пользовательском пространстве, и теоретически выполнять лучше, чем streamи уровня ядра, но производительность снова вылетает из windows, как только вы вводите IO, так как stream, который собирается выполнить IO, должен сначала выполнить дорогостоящие тесты, чтобы проверить, будет ли операция блокироваться, и если да, переведите управление в другой stream.

Я утверждаю, что «зеленые streamи» – это идея, чье время давно прошло. Это также похоже на позицию Austin Group (отвечающей за POSIX), которая удалила функции ucontext в POSIX 2008 и рекомендовала замену streamами POSIX (которые теперь являются обязательной функцией).