2 contributors
123 lines3.9 KB
1# ccoroutines
2Coroutines in C, using standard libraries.
3
4## What's Here
5
6### ccoroutines
7The coroutine engine.
8
9### generator
10Provides generators - coroutines which yield values. These are especially useful for nested searches which provide values to a for loop (eg searching for files in a directory tree).
11
12### async
13Provides asynchronous tasks. Each task volunteers to be switched away-from by waiting on a `Async_Future`.
14
15Note that `generator` and `async` can be used together.
16
17## Prerequisites
18
19These rely on as much as possible on C's cross-platform comfort zone. C's standard libraries are used as far as possible, but, as `threads.h` is not usually supported, `pthread.h` has been used instead.
20
21### Style
22
23The style is influenced by C++. For example, where possible, a `Something *Something_New(a, b, c)` and `Something_Delete(Something *)`, where a `Something` is `malloc`ed, will have corresponding `Somthing_ctor(Somthing *, a, b, c)` and `Something_dtor(Something *)` to initialise and finalise a `Something` on the stack, or within another object. Using `.._ctor()` and `.._dtor()` will be faster as they avoid the `malloc()` and `free()`.
24
25 Something *oneofthem = Something_New();
26 // use oneofthem
27 Something_Delete(oneofthem);
28
29Can be also be done like this, and this will run faster:
30
31 Something oneofthem;
32 Something_ctor(&oneofthem);
33 // use oneofthem
34 Something_dtor(&oneofthem);
35
36## Usage
37
38When you are using coroutines or generators:
39
40 void *myfunc(void *){
41 // your function here
42 }
43
44 Coroutine_StartSystem();
45 Coroutine_Run(myfunc, (void *)myparam);
46 Coroutine_StopSystem();
47
48If you also use async, then:
49
50 bool myfunc(void *myparam, void **res){
51 // your async function here
52 }
53
54 Async_StartSystem();
55 void *res = NULL;
56 bool canceled = Async_Run(myfunc, myparam, &res);
57 Async_StopSystem();
58
59While the system is started, you can make many calls to `Coroutine_Run()` or `Async_Run()`. A running system is thread local - each thread you want to use coroutines on will need to be `Coroutine_StartSystem()`ed or `Async_StartSystem()`ed.
60
61### Generators
62
63 void *yield_files(void *param){
64 bool domore = true;
65
66 // loop/call functions to find more values to yield, and when you have one:
67 domore = Generator_Yield(res);
68 // .. if domore is false, exit your generator - it is being destructed
69
70 // not actually used by generators, but this is a useful convention for bubbling
71 // the flag out to calling functions.
72 return (void *)domore;
73 }
74
75 Generator gen;
76 Generator_ctor(&gen, yield_files, "..");
77 int count = 0;
78 void *res;
79 while(Generator_Next(&gen, &res)){
80 // use res - a value yielded by your generator
81 printf("%d) %s\n", count, (char *)res);
82 free(res);
83
84 // exit your loop early if you want to
85 if (++count>16000) break;
86 }
87 Generator_dtor(&gen);
88
89### Async
90
91To run an Async program:
92
93 Async_StartSystem();
94 void *res = NULL;
95 bool canceled = Async_Run(asyncmain, &param, &res);
96 Async_StopSystem();
97
98Async runs tasks, switching between them when the current task waits on an `Async_Future`. The async main is also a task. The entry function for any task looks like this:
99
100 bool asyncmain(void *param, void **res){
101
102 // do your thing here
103
104 return canceled;
105 }
106
107Tasks can complete, or be canceled. Return whether your task was canceled or not.
108
109Within your async task, create `Async_Task`s and `Async_Future_Await()` them when you want to wait for their result. Note that an `Async_Task` has a member, `base`, which is an `Async_Future`, which is what you should wait on:
110
111 bool asyncmain(void *param, void **res){
112 ...
113 Async_Task task1;
114 Async_Task_ctor(&task1, anasynctask, &task1param);
115
116 bool canceled = Async_Future_Await(&task1.base);
117
118 // use the result stored in the future
119
120 Async_Task_dtor(&task1);
121 ...
122 }
123