2 contributors
123 lines3.9 KB
Newer
Older
-
+
commited
{line.log.rev}
on
10 months ago
1
1
# ccoroutines
9 months ago
2
Coroutines in C, using standard libraries.
3
4
## What's Here
5
6
### ccoroutines
7
The coroutine engine.
8
9
### generator
10
Provides 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
13
Provides asynchronous tasks. Each task volunteers to be switched away-from by waiting on a `Async_Future`.
14
15
Note that `generator` and `async` can be used together.
16
17
## Prerequisites
18
19
These 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
23
The 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
29
Can 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
38
When 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
48
If 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
59
While 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
91
To run an Async program:
92
93
Async_StartSystem();
94
void *res = NULL;
95
bool canceled = Async_Run(asyncmain, &param, &res);
96
Async_StopSystem();
97
98
Async 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
107
Tasks can complete, or be canceled. Return whether your task was canceled or not.
108
109
Within 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