{"id":22220597,"url":"https://github.com/fix8mt/fiber","last_synced_at":"2025-09-12T18:15:05.401Z","repository":{"id":44427355,"uuid":"512582405","full_name":"fix8mt/fiber","owner":"fix8mt","description":"C++20 fiber implementation with similar interface to std::thread, header-only / x86_64 / Linux only / stackful / built-in scheduler / thread shareable","archived":false,"fork":false,"pushed_at":"2024-09-18T23:49:20.000Z","size":1543,"stargazers_count":23,"open_issues_count":0,"forks_count":2,"subscribers_count":4,"default_branch":"main","last_synced_at":"2024-09-19T07:03:58.724Z","etag":null,"topics":["boost","c-plus-plus-20","concurrency","cooperative","cooperative-multitasking","coroutine","coroutines","cplusplus","cpp","cpp20","fiber","fibers","header-only","linux","resume","x86-64","yield"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsl-1.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/fix8mt.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-07-11T01:42:12.000Z","updated_at":"2024-05-05T21:16:59.000Z","dependencies_parsed_at":"2024-05-05T22:26:28.125Z","dependency_job_id":"3b3d2078-410c-463a-9488-e9bf179b84b3","html_url":"https://github.com/fix8mt/fiber","commit_stats":null,"previous_names":[],"tags_count":11,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fix8mt%2Ffiber","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fix8mt%2Ffiber/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fix8mt%2Ffiber/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fix8mt%2Ffiber/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fix8mt","download_url":"https://codeload.github.com/fix8mt/fiber/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":227817175,"owners_count":17824199,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["boost","c-plus-plus-20","concurrency","cooperative","cooperative-multitasking","coroutine","coroutines","cplusplus","cpp","cpp20","fiber","fibers","header-only","linux","resume","x86-64","yield"],"created_at":"2024-12-02T23:09:17.824Z","updated_at":"2024-12-02T23:09:18.742Z","avatar_url":"https://github.com/fix8mt.png","language":"C++","readme":"\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://www.fix8mt.com\"\u003e\u003cimg src=\"https://github.com/fix8mt/fiber/blob/main/assets/fix8mt_Master_Logo_Green_Trans.png\" width=\"200\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n# fiber\n\n### A novel C++20 fiber implementation with similar interface to `std::thread`, header-only / `x86_64` / Linux only / stackful / built-in scheduler / thread shareable\n\n------------------------------------------------------------------------\n## Introduction\nThis is a novel fiber implementation with a similar interface to `std::thread`. Taking any [callable](https://en.cppreference.com/w/cpp/named_req/Callable)\nobject, fibers execute and cooperatively yield amongst\nthemselves and the calling function all within a single thread. Using fibers, single threaded applications can be written as though they were multi-threaded,\nwith the advantage that no concurrency controls are required.\nFor multi-threaded applications, each thread maintains its own list of running fibers, leaving the user to implement their own concurrency controls. This\nimplementation allows you to move fibers between threads. This can be used to share work or scale an application by adding more fibers to new or existing threads.\n\nCurrently only `Linux/x86_64` is supported. Other platforms to be supported in the future.\n\n| ![montest2 - example monitor application](https://github.com/fix8mt/fiber/blob/main/assets/fibermonitor1.png) |\n|:--:|\n| Screenshot from *`montest2`* with 20 fibers working in one thread and using `fiber_monitor`|\n\n## Quick links\n|**Link**|**Description**|\n--|--\n|[Wiki]( https://github.com/fix8mt/fiber/wiki)| for complete documentation|\n|[API](https://github.com/fix8mt/fiber/wiki/API)| for API documentation|\n|[Building](https://github.com/fix8mt/fiber/wiki/Building)| for build options and settings|\n|[Monitor](https://github.com/fix8mt/fiber/wiki/Monitor)| for built-in monitor documentation|\n|[Examples](https://github.com/fix8mt/fiber/wiki/Examples)| for details about all the included examples|\n|[Here](https://github.com/fix8mt/fiber/blob/main/include/fix8/fiber.hpp)| for implementation|\n|[Here](https://github.com/fix8mt/fiber/tree/f8_fiber_boost)| for the original `f8fiber` implementation|\n\n## Motivation\n- header-only\n- `std::thread` like interface\n- no external dependencies\n- simplicity, lightweight\n- make use of C++20 features\n- `constexpr` where possible\n- expand and improve interface\n\n## Features\n- **x86_64 Linux only**\n- single _header-only_\n- stackful fibers; stacksize configurable for each fiber\n- supports any callable object (eg. function, class member, lambda expression) with optional arguments\n- heap based, memory-mapped or placement stacks; user definable stack can also be used\n- context switch implemented with inline assembly\n- fibers can be moved to other threads (can be configured out for performance)\n- `std::invoke` style ctor, with arguments perfectly forwarded to the callable\n- extended API, supporting `resume`, `resume_if`, `resume_with`, `kill`, `kill_all`, `suspend`, `schedule`, `join`, `join_if`, `detach`, `resume_main`, `schedule_if`, `move`, `suspend_if`, `wait_all` and more\n- built-in fiber printer\n- optional built-in terminal based monitor\n- helper templates including `async`, `make_fiber`, `launch_all` and `launch_all_with_params` and more\n- supports `fibers` and `this_fiber` namespaces\n- ctor based fiber parameter struct (POD) - including fiber name, custom stack and stack size, launch policy, launch order and auto join\n- built-in round-robin scheduler\n- can be used with `std::packaged_task`, `std::future`, `std::promise` and so forth\n- fast, very lightweight\n- fiber exceptions and general [exception handling](https://github.com/fix8mt/fiber/wiki/API#8-exception-handling)\n- built-in instrumentation (can be configured out for performance)\n- lots of [examples](https://github.com/fix8mt/fiber/wiki/Examples)\n- full [API](https://github.com/fix8mt/fiber/wiki/API) documentation\n- supports `jfiber` (similar to `std::jthread`)\n- works with gcc, clang\n\n# Examples\n## 1. A simple resumable function\nIn the following example each iteration of `main` and `func` simply yields, printing the iteration count before and after each yield.\nNote to pass a reference to the `flags` variable we need to use the `std::ref` wrapper. Before exiting `func` calls the built-in printer.\nWhen `func` exits, control returns to `main` where testing `f0` for non-zero returns false indicating the fiber has finished.\n\nNote that you can name a fiber using `fiber_params`. The default name for the calling thread of a fiber is `main`.\n\n\u003cdetails\u003e\u003csummary\u003e\u003ci\u003esource\u003c/i\u003e\u003c/summary\u003e\n\u003cp\u003e\n\n```c++\n#include \u003ciostream\u003e\n#include \u003ciomanip\u003e\n#include \u003cthread\u003e\n#include \u003cstring\u003e\n#include \u003cfix8/fiber.hpp\u003e\nusing namespace FIX8;\n\nvoid func(bool\u0026 flags, int cnt)\n{\n   std::cout \u003c\u003c '\\t' \u003c\u003c this_fiber::name() \u003c\u003c \" (fiber id:\" \u003c\u003c this_fiber::get_id() \u003c\u003c \")\\n\";\n   for (int kk{}; kk \u003c cnt; ++kk)\n   {\n      std::cout \u003c\u003c '\\t' \u003c\u003c this_fiber::name() \u003c\u003c ':' \u003c\u003c kk \u003c\u003c '\\n';\n      this_fiber::yield();\n      std::cout \u003c\u003c '\\t' \u003c\u003c this_fiber::name() \u003c\u003c ':' \u003c\u003c kk \u003c\u003c \" (resumed)\\n\";\n   }\n   flags = true;\n   fibers::print();\n   std::cout \u003c\u003c '\\t' \u003c\u003c this_fiber::name() \u003c\u003c \":exit\\n\";\n}\n\nint main(int argc, char *argv[])\n{\n   std::cout \u003c\u003c this_fiber::name() \u003c\u003c \":entry (fiber id:\" \u003c\u003c this_fiber::get_id() \u003c\u003c \")\\n\";\n   bool flags{};\n   fiber f0({\"func\"}, \u0026func, std::ref(flags), 5);\n   std::cout \u003c\u003c \"flags=\" \u003c\u003c std::boolalpha \u003c\u003c flags \u003c\u003c '\\n';\n\n   for (int ii{}; f0; ++ii)\n   {\n      std::cout \u003c\u003c this_fiber::name() \u003c\u003c ':' \u003c\u003c ii \u003c\u003c '\\n';\n      this_fiber::yield();\n      std::cout \u003c\u003c this_fiber::name() \u003c\u003c ':' \u003c\u003c ii \u003c\u003c \" (resumed)\\n\";\n   }\n   std::cout \u003c\u003c \"flags=\" \u003c\u003c std::boolalpha \u003c\u003c flags \u003c\u003c '\\n';\n   std::cout \u003c\u003c this_fiber::name() \u003c\u003c \":exit\\n\";\n   return 0;\n}\n```\n\n\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003ci\u003eoutput\u003c/i\u003e\u003c/summary\u003e\n\u003cp\u003e\n\n```bash\n$ ./fibertest0\nmain:entry (fiber id:NaF)\nflags=false\nmain:0\n        func:entry (fiber id:2896)\n        func:0\nmain:0 (resumed)\nmain:1\n        func:0 (resumed)\n        func:1\nmain:1 (resumed)\nmain:2\n        func:1 (resumed)\n        func:2\nmain:2 (resumed)\nmain:3\n        func:2 (resumed)\n        func:3\nmain:3 (resumed)\nmain:4\n        func:3 (resumed)\n        func:4\nmain:4 (resumed)\nmain:5\n        func:4 (resumed)\n#      fid  pfid prev   ctxs      stack ptr    stack alloc    depth  stacksz     flags ord name\n0    * 2896 NaF  NaF       6 0x7f9fb3632ea8 0x7f9fb3613010      352   131072 _________  99 func\n1      NaF  NaF  2896      6 0x7fff7628f8a8              0        0  8388608 m________  99 main\n        func:exit\nmain:5 (resumed)\nflags=true\nmain:exit\n$\n```\n\n\u003c/p\u003e\n\u003c/details\u003e\n\n## 2. A generator class\nThe following example implements a simple [generator](https://en.wikipedia.org/wiki/Generator_(computer_programming)) pattern.\n\nBoth the `producer()` and `consumer()` methods of `foo` are passed as callable objects to the `fiber` members `_produce` and `_consume`.\n\nNote that the fiber ctor requires `this` for pointer to member functions. Also note the additional parameter `num` passed to `_produce`. Your callable object definition\nmust match the parameters passed to fiber.\n\nAfter construction of the fibers, the `foo` ctor calls `_produce.resume()` which immediately switches to `producer()`.\nEach iteration of the for loop generates 5 random numbers that are pushed to a queue after which `producer()` switches to `consumer()`.\n\nNote that `consumer()` will only continue to run while the `_produce` fiber is still running, consuming all numbers pushed to the queue and when empty\nswitching back to `producer()`.\n\nWhen `producer()` has looped `numtogen` times, it calls `_consume.schedule()` which instructs the fiber scheduler to schedule `consumer()` as the next fiber to run;\n`producer()` then exits and `consumer()` is resumed (exiting a fiber causes the scheduler to switch to the next scheduled fiber) -\nbut since the `_produce` fiber has exited, `while (_produce)` will return `false` causing `consumer()` to also exit.\n\n\u003cdetails\u003e\u003csummary\u003e\u003ci\u003esource\u003c/i\u003e\u003c/summary\u003e\n\u003cp\u003e\n\n```c++\n#include \u003cqueue\u003e\n#include \u003crandom\u003e\n#include \u003cfix8/fiber.hpp\u003e\nusing namespace FIX8;\n\nclass foo\n{\n   std::queue\u003clong\u003e _queue;\n   fiber _produce, _consume;\n\n   void producer(int numtogen)\n   {\n      std::cout \u003c\u003c \"\\tproducer:entry (id:\" \u003c\u003c this_fiber::get_id() \u003c\u003c \")\\n\";\n      std::mt19937_64 rnde {std::random_device{}()};\n      auto dist{std::uniform_int_distribution\u003clong\u003e(1, std::numeric_limits\u003clong\u003e().max())};\n      for (; numtogen; --numtogen)\n      {\n         while(_queue.size() \u003c 5)\n            _queue.push(dist(rnde));\n         std::cout \u003c\u003c \"\\tproduced: \" \u003c\u003c _queue.size() \u003c\u003c '\\n';\n         _consume.resume(); // switch to consumer\n      }\n      _consume.schedule(); // consumer is next fiber to run\n      std::cout \u003c\u003c \"\\tproducer:exit\\n\";\n   }\n   void consumer()\n   {\n      std::cout \u003c\u003c \"\\tconsumer:entry (id:\" \u003c\u003c this_fiber::get_id() \u003c\u003c \")\\n\";\n      while (_produce)\n      {\n         int cnt{};\n         while(!_queue.empty())\n         {\n            std::cout \u003c\u003c \"\\t\\t\" \u003c\u003c ++cnt \u003c\u003c \": \" \u003c\u003c _queue.front() \u003c\u003c '\\n';\n            _queue.pop();\n         }\n         std::cout \u003c\u003c \"\\tconsumed: \" \u003c\u003c cnt \u003c\u003c '\\n';\n         _produce.resume(); // switch to producer\n      }\n      std::cout \u003c\u003c \"\\tconsumer:exit\\n\";\n   }\n\npublic:\n   foo(int num) : _produce(\u0026foo::producer, this, num), _consume(\u0026foo::consumer, this)\n   {\n      _produce.resume(); // switch to producer\n   }\n};\n\nint main(int argc, char *argv[])\n{\n   std::cout \u003c\u003c \"main:entry\\n\";\n   foo bar(argc \u003e 1 ? std::stoi(argv[1]) : 10);\n   std::cout \u003c\u003c \"main:exit\\n\";\n   return 0;\n}\n```\n\n\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003ci\u003eoutput\u003c/i\u003e\u003c/summary\u003e\n\u003cp\u003e\n\n```bash\n$ ./fibertest22 5\nmain:entry\n  producer:entry (id:4016)\n  produced: 5\n  consumer:entry (id:1968)\n\t 1: 1349602525532272804\n\t 2: 316583067409009491\n\t 3: 1020347932332564514\n\t 4: 3829997051190076899\n\t 5: 947478241006829049\n  consumed: 5\n  produced: 5\n\t 1: 3617976082375098752\n\t 2: 3972849389773859934\n\t 3: 7998668485491537141\n\t 4: 4650831140486621276\n\t 5: 7332043501653828395\n  consumed: 5\n  produced: 5\n\t 1: 2230847709081134901\n\t 2: 6965146163979072417\n\t 3: 6029855094014219769\n\t 4: 1063218563532550271\n\t 5: 1444553618767029414\n  consumed: 5\n  produced: 5\n\t 1: 4198632358838426114\n\t 2: 9056029556599489020\n\t 3: 8320555710292082575\n\t 4: 2721317769035964708\n\t 5: 4913464453217416140\n  consumed: 5\n  produced: 5\n\t 1: 3735451366216011356\n\t 2: 4377846252953671965\n\t 3: 5218125716664024839\n\t 4: 6370858901001428693\n\t 5: 6699210929525116824\n  consumed: 5\n  producer:exit\n  consumer:exit\nmain:exit\n$\n```\n\n\u003c/p\u003e\n\u003c/details\u003e\n\n## 3. Resumable non-blocking message reader\nThis example demonstrates the use of a fiber to incrementally read a message, yielding to the caller when there is insuffient data\nto be read. The caller can perform other processing, and return to the reader to resume reading more of a message. When a message is fully\nread, a process function is called.\n\nThe fiber entry point `read_nb(int rdcnt)` will read `rdcnt` messages. Each message consists of a variable header (length 12 - 16 bytes);\na variable body (length 80 - 102) and a fixed length trailer (length 10). Bytes are chosen randomly from a Base64 string.\nEach component of the message is read using the method `read_some()`\nwhich will randomly choose to _not_ fully complete a read (50% of the time), randomly reading some count less than requested. Reading will continue, yielding to\nthe caller when insufficient data is available.\n\n`read_some()` will also randomly throw a `std::runtime_error`. `read_nb()` catches any exception and assigns it to a `std::exception_ptr`. If\nan exception is caught, the method will not attempt to read any more messages, exiting the fiber and returning to `main`. When control is\nreturned, `main` checks for a non-empty `std::exception_ptr` and rethrows the stored exception. `main` will continue to yield to the reader\n(`resume()`) while the reader fiber is still running (`while (reader)`).\n\nNote our reader class inherits from `fiber`, and constructs the fiber with a pointer to a member class, a `this` and an integer\nparameter.\n\n\u003cdetails\u003e\u003csummary\u003e\u003ci\u003esource\u003c/i\u003e\u003c/summary\u003e\n\u003cp\u003e\n\n```c++\n#include \u003ciostream\u003e\n#include \u003ciomanip\u003e\n#include \u003carray\u003e\n#include \u003cstring\u003e\n#include \u003cstring_view\u003e\n#include \u003crandom\u003e\n#include \u003cexception\u003e\n#include \u003cfix8/fiber.hpp\u003e\nusing namespace FIX8;\n\nclass Reader : public fiber\n{\n   static constexpr std::string_view b64set{ \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\" };\n   static const int _max_msg_len{256}, _trl_len{10};\n   std::exception_ptr _eptr;\n   std::mt19937 _rnd_engine{ std::random_device{}() }; // uses /dev/urandom\n   std::uniform_int_distribution\u003cint\u003e _chardist{0, b64set.size() - 1}, _hdrdist{12, 16}, _mlendist{80, 102};\n\n   // simulate a read that doesn't guarentee to read all that was requested\n   int read_some(char *where, int cnt)\n   {\n      // 50% will not read all requested (will resume and try again)\n      if (std::bernoulli_distribution()(_rnd_engine))\n         cnt = std::uniform_int_distribution\u003cint\u003e{0, cnt - 1}(_rnd_engine);\n      if (cnt \u0026\u0026 std::bernoulli_distribution(.002)(_rnd_engine)) // 0.2% chance of a read exception\n         throw std::runtime_error(\"exception reading \" + std::to_string(cnt) + \" bytes\");\n      for (const auto ptr{ where + cnt }; where \u003c ptr; ++where)\n         *where = b64set[_chardist(_rnd_engine)];\n      return cnt;\n   }\n\n   // override to process message\n   virtual void process (std::string_view msg) const\n   {\n      std::cout \u003c\u003c std::setw(3) \u003c\u003c msg.size() \u003c\u003c ' ' \u003c\u003c msg \u003c\u003c '\\n';\n   }\n\n   // non-blocking resumable reader\n   void read_nb(int rdcnt)\n   {\n      int mread{};\n      try\n      {\n         for (std::array\u003cchar, _max_msg_len\u003e buff; mread \u003c rdcnt; ++mread)\n         {\n            auto hlen{ _hdrdist(_rnd_engine) }, mlen{ _mlendist(_rnd_engine) }; // variable header and body length\n\n            // read header(var length), yield if nothing or insufficient to read\n            for (int sofar{}; (sofar += read_some(buff.data() + sofar, hlen - sofar)) \u003c hlen;)\n               this_fiber::yield();\n            buff[hlen++] = ' '; // separator\n\n            // read body(var length), yield if nothing or insufficient to read\n            for (int sofar{}; (sofar += read_some(buff.data() + hlen + sofar, mlen - sofar)) \u003c mlen;)\n               this_fiber::yield();\n            buff[hlen + mlen++] = ' '; // separator\n\n            // read trailer(fixed length), yield if nothing or insufficient to read\n            for (int sofar{}; (sofar += read_some(buff.data() + hlen + sofar + mlen, _trl_len - sofar)) \u003c _trl_len;)\n               this_fiber::yield();\n\n            process(std::string_view(buff.data(), hlen + mlen + _trl_len));\n         }\n      }\n      catch (...)\n      {\n         _eptr = std::current_exception();\n      }\n      std::cout \u003c\u003c \"read_nb: \" \u003c\u003c mread \u003c\u003c \" messages read\\n\";\n   }\n\npublic:\n   Reader(int rdcnt) : fiber(\u0026Reader::read_nb, this, rdcnt) {}\n   std::exception_ptr get_exception() const { return _eptr; }\n};\n\nint main(int argc, char *argv[])\n{\n   try\n   {\n      Reader reader(argc \u003e 1 ? std::stoi(argv[1]) : 100);\n      while (reader)\n      {\n         reader.resume();\n         try\n         {\n            if (reader.get_exception())\n               std::rethrow_exception(reader.get_exception());\n         }\n         catch (const std::exception\u0026 e)\n         {\n            std::cerr \u003c\u003c \"Reader: \" \u003c\u003c e.what() \u003c\u003c '\\n';\n         }\n         catch (...)\n         {\n            std::cerr \u003c\u003c \"Reader: unknown exception\\n\";\n         }\n      }\n      std::cout \u003c\u003c reader.get_ctxswtchs() \u003c\u003c \" yields\\n\";\n   }\n   catch (const std::exception\u0026 e)\n   {\n      std::cerr \u003c\u003c \"main: \" \u003c\u003c e.what() \u003c\u003c '\\n';\n   }\n   return 0;\n}\n```\n\n\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003ci\u003eoutput\u003c/i\u003e\u003c/summary\u003e\nIn this example, 20 messages were requested however an exception was thrown reading the 13th message, and reading stopped. Note also the number\nof yields back to the caller are reported.\n\u003cp\u003e\n\n```bash\n$ ./fibertest26 20\n124 LctFjN/09NBZ mDPtFqvztmHWflL67CqtFWiJmG6FKsYgEnMzDRPCf0xm5FysuVHh+x0NrSISh4Z9p4PptyxP+w1ewI4rsBAAG8Hb76nbKbt8yLNg NhDTxR2Asw\n113 1mx5RNdVJisFj lEc8IFOQ1uvlV2e8w5WOjT4+I3atpf6cor4pW6qAhggUQ6nIoGbM+BVTZ8bsjoLVNmIVoQIH/G1P5etK0gEg7cIa 2YI/4unCoF\n114 mCQ7o0gV+oC6 ljEQArWk+9Z5Kk0tZasyowLb7rBAJH7Ien/MqXT6hqI7ycrSCVtf9ObUotjTgLpWpF77dGD3u478gPTwHEIKbw8Bg8 uIGaY/BghC\n106 DuIReo+2HZqC XvCz4YEh+gsKD9hKlaMy7PWxB8LThVQGtOVEyJ7TBp5HwKEYJkOwauOU0YjPmUjEnKFDxwubv2RVtM8u/0 3xEcEbzrXl\n109 fTmQIoTJ2Cd0E+p LwwawaUbyvHG+3hqFDHL41pDTrM1tA3VRO2LCK/ppCCdBb8DQqVUiVI3iXL9zZ489jjtRNmP7LiuHbhxdo 7fp38/3mQX\n130 GuTL6VWln+voJ+w5 Xkk4NRoWvLHUo40qBF09I6sbN0PJ/YRXBWab0iiwhGrl9ylgq/3jcm17j5iJIvzVzdvup+IOMh+ScVHQ4EeibkSgI9UwI0r9tHJh6s IaNuK3ZDLh\n123 JEtJ8Q8ypfHshtZ0 OBz39mjNSfy0Gvnf1cmhT0iSY5pGzG+ovr24QVFE2CDNgjCV8+qzzGCrcMMhSoToL6UqTC0T/SHO2zt8DtvVARq6HrjZsGl CdDavW90LN\n127 jgHj1nd9QZe5HH Q618VjDY8dz7VNOCuGrHELFoJ2UIFbKBf+otemUv6mxAksA06sdd6Y3CG7SeuxGrHnjNo4xI+/6O73AEiYpI0xl+8Lrtk4w6B8OP8 v5y9/oAcKz\n126 OLDdCx1fnURzM/fl HcdeeLbOc5bG9oTbogTdn2eiduU/NuDoojEn2/RrF0bXPl+sernRHXHbukASoBFYdpxVm1CMYRC4KoeKEueQMNeFz9rbcuDjxl 7Nhg9oaAh5\n111 0DK3NYzIokmtHMC tF7Ld99kdIPJYNe/WeCEGqTD20kvJPmeceyVDHbAASaHaQtrFzX8zPcXekBHxujUpi2J50Xr6l0Herd9uQA+ hQs0pwOY8J\n116 PnAEXeLfo68k/ SMBLhvBh5ZqCs+WgLhPEPpzvmt42bsWy/E7HkYqG2BOUe2LgVNdq1aAYVtcfAZ4SJlalNpbA1Lzv0olgweXtqlLx+Z1 rvMDIX+24O\n128 4RvyYIO+VDSalI xMjWP3bKvFAxedgdCaLT605zPW4/eFv2iOhrVrVtnMZSZM4OZjEtg/sBj1iORVtoeLmVBnSSTuoWOIJn7K5avDf6kI3tKxj1N9ESFA EhX45Ucg9X\nread_nb: 12 messages read\nReader: exception reading 5 bytes\n28 yields\n$\n```\n\n\u003c/p\u003e\n\u003c/details\u003e\n\n## 4. Detached fiber workpiece\nIn this example, four detached fibers are created.\n\nWhen main ends, the detached fibers are activated in creation order. Each fiber takes a lambda expression as its callable object,\nwhich prints from an array constructed with every fourth word until the array is exhausted.\n\nNote the ctor for each fiber takes a reference to one of the `string_view` arrays, passed as an argument.\nSee fibertest10.cpp\n\n\u003cdetails\u003e\u003csummary\u003e\u003ci\u003esource\u003c/i\u003e\u003c/summary\u003e\n\u003cp\u003e\n\n```c++\n#include \u003carray\u003e\n#include \u003ciostream\u003e\n#include \u003cfix8/fiber.hpp\u003e\nusing namespace FIX8;\n\nint main()\n{\n   static constexpr const std::array wordset\n   {\n      std::array { R\"(\"I)\",      \"all\",   \"said\",  \"It’s\",     \"I’m\",         \"\\n –\",        },\n      std::array { \"am\",         \"of\",    \"no\",    \"because\",  \"doing\",       \"Albert\",      },\n      std::array { \"thankful\",   \"those\", \"to\",    \"of\",       \"it\",          \"Einstein\\n\"   },\n      std::array { \"for\",        \"who\",   \"me.\",   \"them\",     R\"(myself.\")\", \"\"             },\n   };\n\n   for (const auto\u0026 pp : wordset)\n   {\n      fiber ([](const auto\u0026 words)\n      {\n         for (auto qq : words)\n         {\n            std::cout \u003c\u003c qq \u003c\u003c ' ';\n            this_fiber::yield();\n         }\n      }, pp).detach();\n   }\n\n   return 0;\n}\n```\n\n\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003ci\u003eoutput\u003c/i\u003e\u003c/summary\u003e\n\u003cp\u003e\n\n```bash\n$ ./fibertest10\n\"I am thankful for all of those who said no to me. It’s because of them I’m doing it myself.\"\n – Albert Einstein\n$\n```\n\n\u003c/p\u003e\n\u003c/details\u003e\n\n## 5. Another detached fiber workpiece using `launch_all` and `launch_all_with_params`\nSimilar to the previous example, four detached fibers are created in a new thread. Two versions of this are shown.\n```c++\ntemplate\u003cstd::invocable... Fns\u003e\nconstexpr void launch_all(Fns\u0026\u0026 ...funcs);\n\ntemplate\u003ctypename Ps, std::invocable Fn, typename... Fns\u003e\nconstexpr void launch_all_with_params(Ps\u0026\u0026 params, Fn\u0026\u0026 func, Fns\u0026\u0026 ...funcs);\n```\nTo demonstrate the use of `launch_all` and `launch_all_with_params`,\none example simply creates the fibers in the order they are defined; the second example creates the fibers with a specified launch order (hence the need for\n'with params').\n\nThe `launch_all` and `launch_all_with_params` templates always detach the fibers they create. Two additional versions are also provided - `launch_all_n` and `launch_all_with_params_n`\nwhich create fibers to a supplied container.  See `fibertest27.cpp` for an example.\n\n\u003cdetails\u003e\u003csummary\u003e\u003ci\u003esource\u003c/i\u003e\u003c/summary\u003e\n\u003cp\u003e\n\n```c++\n#include \u003ciostream\u003e\n#include \u003carray\u003e\n#include \u003cutility\u003e\n#include \u003cfix8/fiber.hpp\u003e\nusing namespace FIX8;\n\nint main()\n{\n   static constexpr const std::array wordsets\n   {\n      std::array { R\"(\"I )\",     \"all \",     \"said \",    \"It’s \",    \"I’m \",        \"\"             },\n      std::array { \"for \",       \"who \",     \"me. \",     \"them \",    \"myself.\\\"\\n\", \"\"             },\n      std::array { \"am \",        \"of \",      \"no \",      \"because \", \"doing \",      \" - Albert \",  },\n      std::array { \"thankful \",  \"those \",   \"to \",      \"of \",      \"it \",         \"Einstein\\n\"   },\n   };\n\n   static const auto func([](const auto\u0026 words)\n   {\n      for (auto pp : words)\n      {\n         std::cout \u003c\u003c pp;\n         this_fiber::yield();\n      }\n   });\n\n   std::thread([]()\n   {\n      launch_all // will print in fiber work order\n      (\n         std::bind(func, wordsets[0]),\n         std::bind(func, wordsets[1]),\n         std::bind(func, wordsets[2]),\n         std::bind(func, wordsets[3])\n      );\n   }).join();\n\n   launch_all_with_params // will print in specified order\n   (\n      fiber_params{.launch_order=0}, std::bind(func, wordsets[0]),\n      fiber_params{.launch_order=3}, std::bind(func, wordsets[1]),\n      fiber_params{.launch_order=1}, std::bind(func, wordsets[2]),\n      fiber_params{.launch_order=2}, std::bind(func, wordsets[3])\n   );\n\n   return 0;\n}\n```\n\n\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003ci\u003eoutput\u003c/i\u003e\u003c/summary\u003e\n\u003cp\u003e\n\n```bash\n$ ./fibertest12\n\"I for am thankful all who of those said me. no to It’s them because of I’m myself.\"\ndoing it  - Albert Einstein\n\"I am thankful for all of those who said no to me. It’s because of them I’m doing it myself.\"\n - Albert Einstein\n$\n```\n\n\u003c/p\u003e\n\u003c/details\u003e\n\n## 6. Example with `std::packaged_task` and `std::future`\nUsing `std::packaged_task` we create a task - a lambda expression taking an int and returning an int. We then obtain a `std::future` from the task, and `std::move`\nthe task to a `fiber`. The fiber will call the task execute operator.\n\nThe fiber and main switch control between each other until the fiber has completed. When it completes, it returns a value which the task makes available to the future.\nThis value is then obtained by the call to `myfuture.get()`.\n\n\u003cdetails\u003e\u003csummary\u003e\u003ci\u003esource\u003c/i\u003e\u003c/summary\u003e\n\u003cp\u003e\n\n```c++\n#include \u003cfunctional\u003e\n#include \u003cfuture\u003e\n#include \u003cfix8/fiber.hpp\u003e\nusing namespace FIX8;\n\nint main(void)\n{\n   std::packaged_task task([](int arg)\n   {\n      std::cout \u003c\u003c \"\\tstarting sub\\n\";\n      for (int ii{}; ii \u003c arg; this_fiber::yield())\n         std::cout \u003c\u003c \"\\tsub: \" \u003c\u003c ++ii \u003c\u003c '\\n';\n      std::cout \u003c\u003c \"\\tleaving sub\\n\";\n      return arg * 100;\n   });\n   auto myfuture { task.get_future() };\n   fiber myfiber(std::move(task), 10);\n   for (int ii{}; myfiber; this_fiber::yield())\n      std::cout \u003c\u003c \"main: \" \u003c\u003c ++ii \u003c\u003c '\\n';\n   std::cout \u003c\u003c \"Future result = \" \u003c\u003c myfuture.get() \u003c\u003c \"\\nExiting from main\\n\";\n   return 0;\n}\n```\n\n\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003ci\u003eoutput\u003c/i\u003e\u003c/summary\u003e\n\u003cp\u003e\n\n```bash\n$ ./fibertest3\nmain: 1\n        starting sub\n        sub: 1\nmain: 2\n        sub: 2\nmain: 3\n        sub: 3\nmain: 4\n        sub: 4\nmain: 5\n        sub: 5\nmain: 6\n        sub: 6\nmain: 7\n        sub: 7\nmain: 8\n        sub: 8\nmain: 9\n        sub: 9\nmain: 10\n        sub: 10\nmain: 11\n        leaving sub\nFuture result = 1000\nExiting from main\n$\n```\n\n\u003c/p\u003e\n\u003c/details\u003e\n\n## 7. Resuming with a different callable object\nThis example is similar to example #1. However, after a few iterations, the main function resumes the fiber with a new function (in fact it is the\nsame function with different arguments). The original function stack is completely overwritten by the new resumed function. To demonstrate the impact of this on\nthe stack, a simple object is created that takes a single integer parameter. The ctor shows the parameter value and its address. Note that when the\nnew resumed function is called, the value is different but the address is the same. Note the dtor for `foo(10)` is never called. It is important\nto keep this in mind when using `resume_with`.\n\nAlso note that in order to rename the fiber, we must use `set_params()`. This can be conveniently bundled with the `resume_with()` call since it returns a `fiber\u0026`.\nThe usual test for a running fiber is used to signal the exiting of the application.\n\n\u003cdetails\u003e\u003csummary\u003e\u003ci\u003esource\u003c/i\u003e\u003c/summary\u003e\n\u003cp\u003e\n\n```c++\n#include \u003ciostream\u003e\n#include \u003cstring\u003e\n#include \u003cfix8/fiber.hpp\u003e\nusing namespace FIX8;\n\nstruct foo\n{\n   int _a;\n   foo(int a) : _a(a) { std::cout \u003c\u003c \"foo(\" \u003c\u003c _a \u003c\u003c \",\u0026_a=\" \u003c\u003c \u0026_a \u003c\u003c \")\\n\"; }\n   ~foo() { std::cout \u003c\u003c \"~foo(\" \u003c\u003c _a \u003c\u003c \")\\n\"; }\n};\n\nvoid sub(int arg, int spacer)\n{\n   foo a(arg);\n   const auto tabs { std::string(spacer, '\\t') };\n   std::cout \u003c\u003c tabs \u003c\u003c \"starting \" \u003c\u003c this_fiber::name() \u003c\u003c '\\n';\n   for (int ii{}; ii \u003c arg; )\n   {\n      std::cout \u003c\u003c tabs \u003c\u003c this_fiber::name() \u003c\u003c \": \" \u003c\u003c ++ii \u003c\u003c '\\n';\n      this_fiber::yield();\n   }\n   std::cout \u003c\u003c tabs \u003c\u003c \"leaving \" \u003c\u003c this_fiber::name() \u003c\u003c '\\n';\n}\n\nint main()\n{\n   int ii{};\n   for (fiber myfiber({\"sub\"}, \u0026sub, 10, 1); myfiber; this_fiber::yield())\n   {\n      std::cout \u003c\u003c \"main: \" \u003c\u003c ++ii \u003c\u003c '\\n';\n      if (ii == 9)\n      {\n         myfiber.set_params(\"sub1\").resume_with(\u0026sub, 5, 2);\n         for (int jj{}; myfiber; this_fiber::yield())\n            std::cout \u003c\u003c \"main1: \" \u003c\u003c ++jj \u003c\u003c '\\n';\n      }\n   }\n   std::cout \u003c\u003c \"Exiting from main\\n\";\n   return 0;\n}\n```\n\n\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003ci\u003eoutput\u003c/i\u003e\u003c/summary\u003e\n\u003cp\u003e\n\n```bash\n$ ./fibertest8\nmain: 1\nfoo(10,\u0026_a=0x7f91323b9f8c)\n        starting sub\n        sub: 1\nmain: 2\n        sub: 2\nmain: 3\n        sub: 3\nmain: 4\n        sub: 4\nmain: 5\n        sub: 5\nmain: 6\n        sub: 6\nmain: 7\n        sub: 7\nmain: 8\n        sub: 8\nmain: 9\nfoo(5,\u0026_a=0x7f91323b9f8c)\n                starting sub1\n                sub1: 1\nmain1: 1\n                sub1: 2\nmain1: 2\n                sub1: 3\nmain1: 3\n                sub1: 4\nmain1: 4\n                sub1: 5\nmain1: 5\n                leaving sub1\n~foo(5)\nExiting from main\n$\n```\n\n\u003c/p\u003e\n\u003c/details\u003e\n\n## 8. Using `jfiber`\nA `jfiber` differs from a `fiber` in that it automatically joins on destruction, similar to C++20 `std::jthread`. This example demonstrates the difference between the two.\nWith no command line arguments, the application will create a `jfiber` otherwise a normal `fiber` is created. With the normal fiber, `main` will exit before\nthe fiber has completed. The default behaviour is the same as a `std::thread` that has not been joined - `terminate`. But with the `jfiber`, when `main` exits, the jfiber\nwill join, so that the fiber is resumed. When the fiber has finished, the application can end.\n\nNote the use of the helper `make_fiber` and `fiber_ptr`.\n\n\u003cdetails\u003e\u003csummary\u003e\u003ci\u003esource\u003c/i\u003e\u003c/summary\u003e\n\u003cp\u003e\n\n```c++\n#include \u003ciostream\u003e\n#include \u003cfunctional\u003e\n#include \u003cfix8/fiber.hpp\u003e\nusing namespace FIX8;\nusing namespace std::literals;\n\nvoid doit()\n{\n   std::cout \u003c\u003c \"\\tstarting \" \u003c\u003c this_fiber::name() \u003c\u003c '\\n';\n   this_fiber::yield();\n   for(int ii{}; ii \u003c 10; std::this_thread::sleep_for(100ms))\n      std::cout \u003c\u003c '\\t' \u003c\u003c this_fiber::name() \u003c\u003c \": \" \u003c\u003c ++ii \u003c\u003c '\\n';\n   std::cout \u003c\u003c \"\\tleaving \" \u003c\u003c this_fiber::name() \u003c\u003c '\\n';\n}\n\nint main(int argc, char *argv[])\n{\n   fiber_ptr fb { argc \u003e 1 ? make_fiber({\"fiber\"}, \u0026doit) : make_fiber\u003cjfiber\u003e({\"jfiber\"}, \u0026doit) };\n   this_fiber::yield();\n   fibers::print();\n   std::cout \u003c\u003c \"Exiting from main\\n\";\n   return 0;\n}\n```\n\n\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003ci\u003eoutput\u003c/i\u003e\u003c/summary\u003e\n\u003cp\u003e\n\n```bash\n$ ./fibertest25 1\n        starting fiber\n#      fid  pfid prev   ctxs      stack ptr    stack alloc     depth  stacksz     flags ord name\n0    * NaF  NaF  2544      2 0x7ffffe9423a8              0        0  8388608 m________  99 main\n1      2544 NaF  NaF       1 0x7fa75c873e58 0x7fa75c854010      432   131072 _________  99 fiber\nExiting from main\nfiber has exited. Terminating application.\nterminate called without an active exception\nAborted (core dumped)\n$\n$ ./fibertest25\n        starting jfiber\n#      fid  pfid prev   ctxs      stack ptr    stack alloc    depth  stacksz     flags ord name\n0    * NaF  NaF  5168      2 0x7ffe8e345e68              0        0  8388608 m________  99 main\n1      5168 NaF  NaF       1 0x7fe177935e58 0x7fe177916010      432   131072 ______j__  99 jfiber\nExiting from main\n        jfiber: 1\n        jfiber: 2\n        jfiber: 3\n        jfiber: 4\n        jfiber: 5\n        jfiber: 6\n        jfiber: 7\n        jfiber: 8\n        jfiber: 9\n        jfiber: 10\n        leaving jfiber\n$\n```\n\n\u003c/p\u003e\n\u003c/details\u003e\n\n## 9. Moving a fiber to another thread\nIn this example we are creating two fibers in the main thread and another fiber in a different thread. All fibers are executing the same function which loops 10 times, yielding on each iteration.\nEach fiber prints the iteration count, as does the main fiber in both threads.\nAfter five loops, the main thread moves one of its fibers to the other thread (`t1`). At various intervals, both threads `fibers::print()` showing which thread has which fibers:\n- The first print shows the second thread's `main` and `first` fibers.\n- The second print shows the main thread's `main`, `first` and `second` fibers.\n- The third print shows the remaining main thread's fibers `main` and `second` (after `first` was moved to the other thread).\n- The fourth print shows the remaining main thread's fibers `main` (after `second` has finished).\n- The fifth print shows the second thread's fibers `main`, `thread:first` and `first` (after `first` has been moved to this thread).\n\nWhen the main thread finishes, it does a thread join, and waits till the second thread has finished.\n\n\u003cdetails\u003e\u003csummary\u003e\u003ci\u003esource\u003c/i\u003e\u003c/summary\u003e\n\u003cp\u003e\n\n```c++\n#include \u003cthread\u003e\n#include \u003cfix8/fiber.hpp\u003e\nusing namespace FIX8;\nusing namespace std::chrono_literals;\n\nvoid sub(int arg)\n{\n   std::cout \u003c\u003c \"\\tstarting \" \u003c\u003c this_fiber::name() \u003c\u003c '\\n';\n   for (int ii{}; ii \u003c arg; this_fiber::yield())\n   {\n      std::cout \u003c\u003c '\\t' \u003c\u003c std::this_thread::get_id() \u003c\u003c ' ' \u003c\u003c this_fiber::name() \u003c\u003c ' ' \u003c\u003c ++ii \u003c\u003c '\\n';\n      std::this_thread::sleep_for(250ms);\n   }\n   std::cout \u003c\u003c \"\\tleaving \" \u003c\u003c this_fiber::name() \u003c\u003c '\\n';\n}\n\nint main(void)\n{\n   fiber f0({\"first\"}, \u0026sub, 10), f2({\"second\"}, \u0026sub, 10);\n   std::thread t1([]()\n   {\n      jfiber ft1({\"thread:first\"}, \u0026sub, 10);\n      for (int ii{}; fibers::has_fibers(); ++ii)\n      {\n         std::cout \u003c\u003c \"main1 \" \u003c\u003c ii \u003c\u003c '\\n';\n         switch(ii)\n         {\n         case 1:\n         case 9:\n            fibers::print();\n            [[fallthrough]];\n         default:\n            std::this_thread::sleep_for(250ms);\n            this_fiber::yield();\n            break;\n         }\n      }\n      std::cout \u003c\u003c std::this_thread::get_id() \u003c\u003c \" Exiting from main1\\n\";\n   });\n\n   std::this_thread::sleep_for(100ms);\n\n   for (int ii{}; fibers::has_fibers(); ++ii)\n   {\n      std::cout \u003c\u003c \"main \" \u003c\u003c ii \u003c\u003c '\\n';\n      switch(ii)\n      {\n      case 5:\n         std::cout \u003c\u003c \"transferring \" \u003c\u003c f0.get_id() \u003c\u003c \" from \"\n            \u003c\u003c std::this_thread::get_id() \u003c\u003c \" to \" \u003c\u003c t1.get_id() \u003c\u003c '\\n';\n         f0.move(t1.get_id());\n         break;\n      case 4:\n      case 9:\n         fibers::print();\n         [[fallthrough]];\n      default:\n         this_fiber::yield();\n         break;\n      }\n   }\n   std::cout \u003c\u003c \"waiting at join...\\n\";\n   fibers::print();\n   t1.join();\n   std::cout \u003c\u003c std::this_thread::get_id() \u003c\u003c \" Exiting from main\\n\";\n   return 0;\n}\n```\n\n\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003ci\u003eoutput\u003c/i\u003e\u003c/summary\u003e\n\u003cp\u003e\n\n```bash\n$ ./fibertest24\nmain1 0\nmain 0\n        starting first\n        140162105964928 first 1\n        starting thread:first\n        140162099050176 thread:first 1\n        starting second\n        140162105964928 second 1\nmain1 1\nThread id 140162099050176\n#      fid  pfid prev   ctxs      stack ptr    stack alloc    depth  stacksz     flags ord name\n0    * NaF  NaF  640       2 0x7f7a081fea18              0        0  8388608 m________  99 main\n1      640  NaF  NaF       1 0x7f7a000209e8 0x7f7a00000ba0      432   131072 ______j__  99 thread:first\nmain 1\n        140162105964928 first 2\n        140162099050176 thread:first 2\n        140162105964928 second 2\nmain1 2\nmain 2\n        140162105964928 first 3\n        140162099050176 thread:first 3\n        140162105964928 second 3\nmain1 3\nmain 3\n        140162105964928 first 4\n        140162099050176 thread:first 4\n        140162105964928 second 4\nmain1 4\nmain 4\nThread id 140162105964928\n#      fid  pfid prev   ctxs      stack ptr    stack alloc    depth  stacksz     flags ord name\n0    * NaF  NaF  9152      5 0x7ffc66f3bb38              0        0  8388608 m________  99 main\n1      2736 NaF  NaF       4 0x7f7a088e2e58 0x7f7a088c3010      432   131072 _________  99 first\n2      9152 NaF  2736      4 0x7f7a08893e58 0x7f7a08874010      432   131072 _________  99 second\n        140162105964928 first 5\n        140162099050176 thread:first 5\n        140162105964928 second 5\nmain1 5\nmain 5\ntransferring 2736 from 140162105964928 to 140162099050176\n        140162105964928 second 6\n        140162099050176 thread:first 6\nmain 6\n        140162105964928 second 7\n        140162099050176 first 6\nmain 7\n        140162105964928 second 8\nmain1 6\nmain 8\n        140162105964928 second 9\n        140162099050176 thread:first 7\nmain 9\nThread id 140162105964928\n#      fid  pfid prev   ctxs      stack ptr    stack alloc    depth  stacksz     flags ord name\n0    * NaF  NaF  9152     10 0x7ffc66f3bb38              0        0  8388608 m________  99 main\n1      9152 NaF  NaF       9 0x7f7a08893e58 0x7f7a08874010      432   131072 _________  99 second\n        140162105964928 second 10\n        140162099050176 first 7\nmain 10\n        leaving second\nmain 11\nwaiting at join...\nThread id 140162105964928\n#      fid  pfid prev   ctxs      stack ptr    stack alloc    depth  stacksz     flags ord name\n0    * NaF  NaF  9152     12 0x7ffc66f3bb38              0        0  8388608 m________  99 main\nmain1 7\n        140162099050176 thread:first 8\n        140162099050176 first 8\nmain1 8\n        140162099050176 thread:first 9\n        140162099050176 first 9\nmain1 9\nThread id 140162099050176\n#      fid  pfid prev   ctxs      stack ptr    stack alloc    depth  stacksz     flags ord name\n0    * NaF  NaF  2736     10 0x7f7a081fea18              0        0  8388608 m________  99 main\n1      640  NaF  NaF       9 0x7f7a000209e8 0x7f7a00000ba0      432   131072 ______j__  99 thread:first\n2      2736 NaF  640       9 0x7f7a088e2e58 0x7f7a088c3010      432   131072 ________v  99 first\n        140162099050176 thread:first 10\n        140162099050176 first 10\nmain1 10\n        leaving thread:first\n        leaving first\nmain1 11\n140162099050176 Exiting from main1\n140162105964928 Exiting from main\n$\n```\n\n\u003c/p\u003e\n\u003c/details\u003e\n\n## 10. Creating fibers using different callable objects\nThis example creates 6 fibers:\n| **Var** | **Type** | **Description** | **Parameters** |\n--|--|--|--\n| `sub_co` | function | Creates fiber with stacksz=2048 calling function `void doit(int arg)` | `3` |\n| `sub_co1` | member function | Creates fiber with stacksz=16384 calling `void foo::sub2()` | `sub2` calls `doit(4)` |\n| `sub_co2` | member function | Creates fiber with stacksz=32768 calling `void foo::sub(int arg)` | `5` |\n| `sub_co3` | member function | Creates fiber with stacksz=8192 calling `void foo::sub1(int arg, const char *str)` | `8.0`, \"hello\"|\n| `sub_co4` | member function | Creates fiber calling `void foo::sub3(int arg, const char *str)` | `12`, \"there\"|\n| `sub_lam` | lambda | Creates fiber named \"sub lambda\" with mapped stack with default stacksz calling supplied lambda | `15` |\n\nOnce the fibers have been created, the main loop begins. Each iteration simply yields, allowing one of the fibers to execute. The `has_fibers` function\nreturns true if any runnable fibers are available. Note that the first iteration performs some specific action - calling print then switching to `sub_co3`. When control\nfinally returns to main another print is performed. Examining the two print outputs reveals the changes that have occurred in the fiber manager. Also\nnote that since `sub_co3` is the first fiber to actually execute, you can see the string `hello` printed followed by `sub8` (which is the number of\niterations that `sub_co3` will perform).\n\nNotice each fiber uses `this_fiber::name` to name itself with exception of `sub_lam` which uses `fiber_params` to name itself.\n\nEach of the fibers prints a start message and loops for a different number of times, printing each iteration each time and\nfinally printing a leaving message before finishing. Main similarly prints each iteration.\n\nIn fiber `sub_co4`, the fiber is suspended for 100ms each loop. This means that other fibers will get a larger share of the available cpu.\nEventually only this fiber is left running as can be seen by the `sub12` messages.\n\nThe sizes of various objects are printed at the end.\n\n\u003cdetails\u003e\u003csummary\u003e\u003ci\u003esource\u003c/i\u003e\u003c/summary\u003e\n\u003cp\u003e\n\n```c++\n#include \u003ciostream\u003e\n#include \u003cfunctional\u003e\n#include \u003cfix8/fiber.hpp\u003e\nusing namespace FIX8;\nusing namespace std::literals;\n\nvoid doit(int arg)\n{\n   std::cout \u003c\u003c this_fiber::name(\"sub\"s + std::to_string(arg));\n   std::cout \u003c\u003c \"\\tstarting \" \u003c\u003c arg \u003c\u003c '\\n';\n   for (int ii{}; ii \u003c arg; )\n   {\n      std::cout \u003c\u003c '\\t' \u003c\u003c this_fiber::name() \u003c\u003c ' ' \u003c\u003c arg \u003c\u003c \": \" \u003c\u003c ++ii \u003c\u003c '\\n';\n      this_fiber::yield();\n   }\n   std::cout \u003c\u003c \"\\tleaving \" \u003c\u003c arg \u003c\u003c '\\n';\n   fibers::print();\n}\n\nstruct foo\n{\n   void sub(int arg)\n   {\n      doit(arg);\n   }\n   void sub1(int arg, const char *str)\n   {\n      std::cout \u003c\u003c str \u003c\u003c '\\n';\n      doit(arg);\n   }\n   void sub3(int arg, const char *str)\n   {\n      auto st { \"sub\"s + std::to_string(arg) };\n      this_fiber::name(st);\n      std::cout \u003c\u003c \"\\tsub2 starting \" \u003c\u003c arg \u003c\u003c '\\n';\n      for (int ii{}; ii \u003c arg; )\n      {\n         std::cout \u003c\u003c '\\t' \u003c\u003c this_fiber::name() \u003c\u003c ' ' \u003c\u003c arg \u003c\u003c \": \" \u003c\u003c ++ii \u003c\u003c '\\n';\n         //this_fiber::sleep_until(std::chrono::steady_clock::now() + 500ms);\n         this_fiber::sleep_for(100ms);\n      }\n      std::cout \u003c\u003c \"\\tsub2 leaving \" \u003c\u003c arg \u003c\u003c '\\n';\n   }\n   void sub2()\n   {\n      doit(4);\n   }\n};\nint main(void)\n{\n   foo bar;\n   fiber sub_co({.stacksz=2048}, \u0026doit, 3),\n         sub_co1({.stacksz=16384}, \u0026foo::sub2, \u0026bar),\n         sub_co2({.stacksz=32768}, \u0026foo::sub, \u0026bar, 5),\n         sub_co3({.stacksz=8192}, \u0026foo::sub1, \u0026bar, 8., \"hello\"),\n         sub_co4(std::bind(\u0026foo::sub3, \u0026bar, 12, \"there\"));\n   fiber sub_lam({.name=\"sub lambda\",.stack=std::make_unique\u003cf8_fixedsize_mapped_stack\u003e()}, [](int arg)\n   //char stack[4096];\n   //fiber sub_lam({.name=\"sub lambda\",.stacksz=sizeof(stack),.stack=std::make_unique\u003cf8_fixedsize_placement_stack\u003e(stack)}, [](int arg)\n   {\n      std::cout \u003c\u003c \"\\tlambda starting \" \u003c\u003c arg \u003c\u003c '\\n';\n      for (int ii{}; ii \u003c arg; )\n      {\n         std::cout \u003c\u003c '\\t' \u003c\u003c this_fiber::name() \u003c\u003c ' ' \u003c\u003c arg \u003c\u003c \": \" \u003c\u003c ++ii \u003c\u003c '\\n';\n         this_fiber::yield();\n      }\n      std::cout \u003c\u003c \"\\tlambda leaving \" \u003c\u003c arg \u003c\u003c '\\n';\n   }, 15);\n   for (int ii{}; fibers::has_fibers(); ++ii)\n   {\n      if (ii == 0)\n      {\n         fibers::print(std::cout);\n         sub_co3.resume();\n         fibers::print(std::cout);\n      }\n      this_fiber::yield();\n      std::cout \u003c\u003c \"main: \" \u003c\u003c std::dec \u003c\u003c ii \u003c\u003c '\\n';\n   }\n   std::cout \u003c\u003c \"Exiting from main\\nSizes\\n\";\n   std::cout \u003c\u003c \"fiber: \" \u003c\u003c sizeof(fiber) \u003c\u003c '\\n';\n   std::cout \u003c\u003c \"fiber::cvars: \" \u003c\u003c sizeof(fiber::cvars) \u003c\u003c '\\n';\n   std::cout \u003c\u003c \"fiber::all_cvars: \" \u003c\u003c sizeof(fiber::all_cvars) \u003c\u003c '\\n';\n   std::cout \u003c\u003c \"fiber_id: \" \u003c\u003c sizeof(fiber_id) \u003c\u003c '\\n';\n   std::cout \u003c\u003c \"fiber_base: \" \u003c\u003c sizeof(fiber_base) \u003c\u003c '\\n';\n   std::cout \u003c\u003c\"fiber_params: \" \u003c\u003c sizeof(fiber_params) \u003c\u003c '\\n';\n   return 0;\n}\n```\n\n\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003ci\u003eoutput\u003c/i\u003e\u003c/summary\u003e\n\u003cp\u003e\n\n```\n$ ./fibertest\n#      fid  pfid prev   ctxs      stack ptr    stack alloc    depth  stacksz     flags ord name\n0    * NaF  NaF  NaF       1              0              0        0  8388608 m________  99 main\n1      9072 NaF  NaF       0 0x563f8b3a9690 0x563f8b3a8ee0       72     2048 _____n___  99\n2      2352 NaF  NaF       0 0x563f8b3adb60 0x563f8b3a9bb0       72    16384 _____n___  99\n3      8864 NaF  NaF       0 0x563f8b3b5be0 0x563f8b3adc30       72    32768 _____n___  99\n4      1728 NaF  NaF       0 0x563f8b3b7c40 0x563f8b3b5c90       72     8192 _____n___  99\n5      2976 NaF  NaF       0 0x7f905fc76fc0 0x7f905fc57010       72   131072 _____n___  99\n6      1728 NaF  NaF       0 0x7f905f913fb0 0x7f905f8f4000       72   131072 _____n___  99 sub lambda\nhello\nsub8    starting 8\n        sub8 8: 1\nsub4    starting 4\n        sub4 4: 1\nsub5    starting 5\n        sub5 5: 1\nsub3    starting 3\n        sub3 3: 1\n        sub2 starting 12\n        sub12 12: 1\n        lambda starting 15\n        sub lambda 15: 1\n#      fid  pfid prev   ctxs      stack ptr    stack alloc    depth  stacksz     flags ord name\n0    * NaF  NaF  1728      2 0x7ffebd5d1368              0        0  8388608 m________  99 main\n1      1728 NaF  NaF       1 0x563f8b3b7a68 0x563f8b3b5c90      544     8192 _________  99 sub8\n2      2352 NaF  1728      1 0x563f8b3ad998 0x563f8b3a9bb0      528    16384 _________  99 sub4\n3      8864 NaF  2352      1 0x563f8b3b5a08 0x563f8b3adc30      544    32768 _________  99 sub5\n4      9072 NaF  8864      1 0x563f8b3a94b8 0x563f8b3a8ee0      544     2048 _________  99 sub3\n5      2976 NaF  9072      1 0x7f905fc76dd8 0x7f905fc57010      560   131072 __s______  99 sub12\n6      1728 NaF  2976      1 0x7f905f913e68 0x7f905f8f4000      400   131072 _________  99 sub lambda\n        sub8 8: 2\n        sub4 4: 2\n        sub5 5: 2\n        sub3 3: 2\n        sub lambda 15: 2\nmain: 0\n        sub8 8: 3\n        sub4 4: 3\n        sub5 5: 3\n        sub3 3: 3\n        sub lambda 15: 3\nmain: 1\n        sub8 8: 4\n        sub4 4: 4\n        sub5 5: 4\n        leaving 3\n#      fid  pfid prev   ctxs      stack ptr    stack alloc    depth  stacksz     flags ord name\n0    * 9072 NaF  8864      4 0x563f8b3a94b8 0x563f8b3a8ee0      544     2048 _________  99 sub3\n1      1728 NaF  9072      3 0x7f905f913e68 0x7f905f8f4000      400   131072 _________  99 sub lambda\n2      NaF  NaF  1728      4 0x7ffebd5d1368              0        0  8388608 m________  99 main\n3      1728 NaF  NaF       4 0x563f8b3b7a68 0x563f8b3b5c90      544     8192 _________  99 sub8\n4      2976 NaF  9072      1 0x7f905fc76dd8 0x7f905fc57010      560   131072 __s______  99 sub12\n5      2352 NaF  1728      4 0x563f8b3ad998 0x563f8b3a9bb0      528    16384 _________  99 sub4\n6      8864 NaF  2352      4 0x563f8b3b5a08 0x563f8b3adc30      544    32768 _________  99 sub5\n        sub lambda 15: 4\nmain: 2\n        sub8 8: 5\n        leaving 4\n#      fid  pfid prev   ctxs      stack ptr    stack alloc    depth  stacksz     flags ord name\n0    * 2352 NaF  1728      5 0x563f8b3ad998 0x563f8b3a9bb0      528    16384 _________  99 sub4\n1      8864 NaF  2352      4 0x563f8b3b5a08 0x563f8b3adc30      544    32768 _________  99 sub5\n2      9072 NaF  8864      4 0x563f8b3a9588 0x563f8b3a8ee0      336     2048 _f_______  99 sub3\n3      1728 NaF  9072      4 0x7f905f913e68 0x7f905f8f4000      400   131072 _________  99 sub lambda\n4      NaF  NaF  1728      5 0x7ffebd5d1368              0        0  8388608 m________  99 main\n5      2976 NaF  9072      1 0x7f905fc76dd8 0x7f905fc57010      560   131072 __s______  99 sub12\n6      1728 NaF  NaF       5 0x563f8b3b7a68 0x563f8b3b5c90      544     8192 _________  99 sub8\n        sub5 5: 5\n        sub lambda 15: 5\nmain: 3\n        sub8 8: 6\n        leaving 5\n#      fid  pfid prev   ctxs      stack ptr    stack alloc    depth  stacksz     flags ord name\n0    * 8864 NaF  1728      6 0x563f8b3b5a08 0x563f8b3adc30      544    32768 _________  99 sub5\n1      1728 NaF  8864      5 0x7f905f913e68 0x7f905f8f4000      400   131072 _________  99 sub lambda\n2      2976 NaF  9072      1 0x7f905fc76dd8 0x7f905fc57010      560   131072 __s______  99 sub12\n3      NaF  NaF  1728      6 0x7ffebd5d1368              0        0  8388608 m________  99 main\n4      1728 NaF  NaF       6 0x563f8b3b7a68 0x563f8b3b5c90      544     8192 _________  99 sub8\n        sub lambda 15: 6\nmain: 4\n        sub8 8: 7\n        sub lambda 15: 7\nmain: 5\n        sub8 8: 8\n        sub lambda 15: 8\nmain: 6\n        leaving 8\n#      fid  pfid prev   ctxs      stack ptr    stack alloc    depth  stacksz     flags ord name\n0    * 1728 NaF  NaF       9 0x563f8b3b7a68 0x563f8b3b5c90      544     8192 _________  99 sub8\n1      2976 NaF  9072      1 0x7f905fc76dd8 0x7f905fc57010      560   131072 __s______  99 sub12\n2      1728 NaF  1728      8 0x7f905f913e68 0x7f905f8f4000      400   131072 _________  99 sub lambda\n3      NaF  NaF  1728      9 0x7ffebd5d1368              0        0  8388608 m________  99 main\n        sub lambda 15: 9\nmain: 7\n        sub lambda 15: 10\nmain: 8\n        sub lambda 15: 11\nmain: 9\n        sub lambda 15: 12\nmain: 10\n        sub lambda 15: 13\nmain: 11\n        sub lambda 15: 14\nmain: 12\n        sub lambda 15: 15\nmain: 13\n        lambda leaving 15\nmain: 14\n        sub12 12: 2\nmain: 15\n        sub12 12: 3\nmain: 16\n        sub12 12: 4\nmain: 17\n        sub12 12: 5\nmain: 18\n        sub12 12: 6\nmain: 19\n        sub12 12: 7\nmain: 20\n        sub12 12: 8\nmain: 21\n        sub12 12: 9\nmain: 22\n        sub12 12: 10\nmain: 23\n        sub12 12: 11\nmain: 24\n        sub12 12: 12\nmain: 25\n        sub2 leaving 12\nmain: 26\nmain: 27\nExiting from main\nSizes\nfiber: 16\nfiber::cvars: 248\nfiber::all_cvars: 120\nfiber_id: 8\nfiber_base: 224\nfiber_params: 48\n$\n```\n\n\u003c/p\u003e\n\u003c/details\u003e\n\n## 11. Example from Dilawar's blog \"An Example of Boost Fiber\"\nThe following example is based on [Dilawar's Blog](https://dilawar.github.io/posts/2021/2021-11-14-example-boost-fiber/). The following description is also based on the text in the blog.\n\n\u003eThe program has two lambdas: `print_a` prints a and `print_b` prints b and then launches a thread that prints B (in detached mode).\nWe created a shared variable ii initialized to 0. We use this a global state. We create two detached fibers.\nFirst one keeps calling `print_a` till `ii \u003c 20`. Similarly, the second one loops on `print_b` till `ii \u003c 20`. Both increment ii by 1. When `ii = 20`, both fibers should be able to join.\nLet’s guess the output of this program. It is most likely to be the same as if std::threads were used instead of fiber.\nX is printed first? Yes. Note that `detach()` is called on each fibers so neither of their functions are called. They are put in the background.\n\n\u003eControl passes to the fiber manager at return 0; when it asks the fibers to join.\nIn fact, you can put more computations after the `std::cout \u003c\u003c 'X';` statement and it would be computed before any fiber is called.\nAs soon as we try to return from the main, fiber manager is asked to join the fibers. The first fiber awakes, a is printed and the fiber yields the control to the manager.\nFiber manager then wakes up the second fiber (who was waiting in the queue) that prints b and also launched a thread in the background that prints B.\nWe can not be sure if B will be printed immediately after the b (it is a std::thread). `print_b` yields the control and goes to sleep.\nThe fiber manager wakes up first fiber again that calls `print_a` again and a is printed and so on. Note that ii is also incremented every time either of the fibers are called.\nWhen ii hits 20, both fibers terminates and joined and the main function return 0;.\n\n\u003eSo we have `print_a` called 10 times and `print_b` is also called 10 times. In the output, we should have 10 a's, 10 b's and 10 B's. B may not strictly follow b but b must come after the a.\nNote that the location of B is not deterministic.\n\n\u003cdetails\u003e\u003csummary\u003e\u003ci\u003esource\u003c/i\u003e\u003c/summary\u003e\n\u003cp\u003e\n\n```c++\n#include \u003ccstdio\u003e\n#include \u003cthread\u003e\n#include \u003cfix8/fiber.hpp\u003e\nusing namespace FIX8;\n\nint main()\n{\n   static int ii{};\n\n   fiber([]() // print_a\n   {\n      do\n      {\n         std::printf(\"%c\", 'a');\n         this_fiber::yield();\n      }\n      while (++ii \u003c 20);\n   }).detach();\n\n   fiber([]() // print_b\n   {\n      do\n      {\n         std::printf(\"%c\", 'b');\n         std::thread([]() { std::printf(\"%c\", 'B'); }).detach();\n         this_fiber::yield();\n      }\n      while (++ii \u003c 20);\n   }).detach();\n\n   std::printf(\"%c\", 'X');\n   return 0;\n}\n```\n\n\u003c/p\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003ci\u003eoutput\u003c/i\u003e\u003c/summary\u003e\n\u003cp\u003e\n\n```bash\n$ ./fibertest7\nXabababBabBBabBababBabBabBBabBaB\n$\n$ ./fibertest7\nXabababBabBBabBabBabBababBabBaBB\n$\n$ ./fibertest7\nXabababBabBBabBabBababBababBBBaB\n$\n```\n\n\u003c/p\u003e\n\u003c/details\u003e\n\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffix8mt%2Ffiber","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffix8mt%2Ffiber","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffix8mt%2Ffiber/lists"}