平台 i386 , win32 , msvc 2003
代码简单介绍:
调度算法:轮转法。。,可修改
内存模型:每个线程拥有各自独立的堆栈。启动线程的时候,切换到对应的堆栈再启动,使得线程之间的堆栈互不干扰
调度方式:线程调用 schedule 函数, schedule 用 setjmp 保存当前堆栈,选择一个新的线程之后用 longjmp 跳转过去。
线程退出:线程函数的返回即意味着线程的退出,可以在线程函数的任何位置上退出。退出后返回到 start_thread 函数里,此后该函数将退出线程的 slot 从链表里删除,如果还有别的线程那么再继续调度,否则跳转出最外层。
堆栈释放:由于线程退出的时候堆栈还在使用,因此无法释放堆栈,所以采用延后一个调度周期的办法,等线程完全结束之后,下一次调用 schedule 的时候释放。
问题:切换线程的时候, longjmp 不会恢复通用寄存器的值,因此要么函数内的局部变量都加上 volatile ,要么在 setjmp 之前手动保存, longjmp 之后手动恢复(可以在库的实现方完成,但是会增大不可移植的面积,现在暂不考虑加入)。
代码:
1
// Cothread.h
2
#include < setjmp.h >
3
4
typedef void ( * thread_func_t)(void * );
5
6
typedef struct sched_slot
7
{
8
jmp_buf buf;
9
int has_set;
10
thread_func_t thread;
11
void * arg;
12
char * stack;
13
} sched_slot;
14
15
16
typedef struct slot_list
17
{
18
sched_slot slot;
19
struct slot_list * next ;
20
} slot_list;
21
22
typedef struct sched_system
23
{
24
slot_list * threads;
25
slot_list * current;
26
int main_esp, main_ebp;
27
char * unfreed_stack;
28
int retaddr;
29
} sched_system;
30
31
32
extern sched_system sys;
33
34
void reg_thread(thread_func_t f, void * arg);
35
36
void free_unfree_stack();
37
38
void schedule();
39
40
void start_first_thread();
41
42
43
44
45
46
47
// cothread.c
48
#include < assert.h >
49
#include < stdlib.h >
50
#include < setjmp.h >
51
#include " cothread.h "
52
#define CHANGE_STACK(newaddr) _asm mov esp, newaddr
53
#define STACK_SIZE 65536
54
#define RESERVED_STACK 4
55
56
57
58
59
60
61
sched_system sys;
62
63
64
void reg_thread(thread_func_t f, void * arg)
65
{
66
slot_list * new_thread = (slot_list * )malloc(sizeof(slot_list));
67
new_thread -> next = sys.threads;
68
sys.threads = new_thread;
69
new_thread -> slot.arg = arg;
70
new_thread -> slot.has_set = 0 ;
71
new_thread -> slot.stack = 0 ;
72
new_thread -> slot.thread = f;
73
}
74
75
76
void free_unfree_stack()
77
{
78
if (sys.unfreed_stack)
79
{
80
free(sys.unfreed_stack);
81
sys.unfreed_stack = 0 ;
82
}
83
}
84
void start_thread(slot_list * iter);
85
86
87
void schedule()
88
{
89
slot_list * old;
90
free_unfree_stack();
91
old = sys.current;
92
sys.current = sys.current -> next ;
93
if (!sys.current)
94
{
95
sys.current = sys.threads;
96
}
97
98
if (!setjmp(old -> slot.buf))
99
{
100
old -> slot.has_set = 1 ;
101
102
if (sys.current -> slot.has_set)
103
longjmp(sys.current -> slot.buf, 1 );
104
else
105
start_thread(sys.current);
106
107
}
108
}
109
110
111
static void exit_thread()
112
{
113
slot_list * iter;
114
free_unfree_stack();
115
if (sys.current == sys.threads)
116
{
117
sys.threads = sys.threads -> next ;
118
sys.unfreed_stack = sys.current -> slot.stack;
119
free(sys.current);
120
sys.current = sys.threads;
121
}
122
else
123
{
124
125
for (iter = sys.threads; iter && iter -> next ! = sys.current && iter -> next ! = 0 ; iter = iter -> next )
126
;
127
assert (iter && iter -> next == sys.current);
128
iter -> next = sys.current -> next ;
129
sys.unfreed_stack = sys.current -> slot.stack;
130
free(sys.current);
131
sys.current = iter -> next ;
132
}
133
134
if (sys.current == 0 )
135
{
136
sys.current = sys.threads;
137
}
138
139
if (sys.current)
140
{
141
142
if (sys.current -> slot.has_set)
143
longjmp(sys.current -> slot.buf, 1 );
144
else
145
start_thread(sys.current);
146
}
147
}
148
149
static jmp_buf buf;
150
151
static void start_thread(slot_list * iter)
152
{
153
char * stack_btm;
154
static thread_func_t thread;
155
static void * arg;
156
157
iter -> slot.stack = (char * )malloc(STACK_SIZE + RESERVED_STACK);
158
stack_btm = iter -> slot.stack + STACK_SIZE;
159
thread = iter -> slot.thread;
160
arg = iter -> slot.arg;
161
CHANGE_STACK(stack_btm);
162
thread(arg);
163
if (sys.threads -> next )
164
exit_thread();
165
else
166
{
167
sys.unfreed_stack = sys.threads -> slot.stack;
168
free(sys.threads);
169
longjmp(buf, 1 );
170
}
171
}
172
173
void start_first_thread()
174
{
175
if (!setjmp(buf))
176
{
177
sys.current = sys.threads;
178
start_thread(sys.current);
179
}
180
free_unfree_stack();
181
}
182
183
184
185
186
187
// 测试代码
188
// test.c
189
190
191
#include < stdio.h >
192
#include < Windows.h >
193
#include " cothread.h "
194
void f0(void * p)
195
{
196
register int i;
197
for (i = 0 ; i < 3 ; ++ i)
198
{
199
printf( " %d, %d"n " , 0 , i);
200
Sleep( 200 );
201
schedule();
202
}
203
// exit_thread();
204
}
205
206
void f1(void * p)
207
{
208
register int i;
209
for (i = 0 ; ; ++ i)
210
{
211
if (i == 6 )
212
return;
213
printf( " %d, %d"n " , 1 , i);
214
Sleep( 200 );
215
schedule();
216
}
217
}
218
219
void f3(void * p)
220
{
221
register int i;
222
for (i = 0 ; i < 6 ; ++ i)
223
{
224
printf( " %d, %d"n " , 3 , i);
225
Sleep( 200 );
226
schedule();
227
}
228
}
229
230
231
void f2(void * p)
232
{
233
register int i;
234
for (i = 0 ;i < 12 ; ++ i)
235
{
236
printf( " %d, %d"n " , 2 , i);
237
Sleep( 200 );
238
schedule();
239
if (i == 8 )
240
{
241
reg_thread(f3, 0 );
242
}
243
}
244
}
245
246
247
248
249
250
int main()
251
{
252
253
254
reg_thread(f0, 0 );
255
reg_thread(f1, 0 );
256
reg_thread(f2, 0 );
257
258
start_first_thread();
259
printf( " finished"n " );
260
getchar();
261
262
}
263
264
posted on 2010-05-30 14:49
何克勤 阅读(1081)
评论(1) 编辑 收藏 所属分类:
Linux 多线程