平臺(tái) i386 , win32 , msvc 2003
代碼簡(jiǎn)單介紹:
調(diào)度算法:輪轉(zhuǎn)法。。,可修改
內(nèi)存模型:每個(gè)線(xiàn)程擁有各自獨(dú)立的堆棧。啟動(dòng)線(xiàn)程的時(shí)候,切換到對(duì)應(yīng)的堆棧再啟動(dòng),使得線(xiàn)程之間的堆棧互不干擾
調(diào)度方式:線(xiàn)程調(diào)用 schedule 函數(shù), schedule 用 setjmp 保存當(dāng)前堆棧,選擇一個(gè)新的線(xiàn)程之后用 longjmp 跳轉(zhuǎn)過(guò)去。
線(xiàn)程退出:線(xiàn)程函數(shù)的返回即意味著線(xiàn)程的退出,可以在線(xiàn)程函數(shù)的任何位置上退出。退出后返回到 start_thread 函數(shù)里,此后該函數(shù)將退出線(xiàn)程的 slot 從鏈表里刪除,如果還有別的線(xiàn)程那么再繼續(xù)調(diào)度,否則跳轉(zhuǎn)出最外層。
堆棧釋放:由于線(xiàn)程退出的時(shí)候堆棧還在使用,因此無(wú)法釋放堆棧,所以采用延后一個(gè)調(diào)度周期的辦法,等線(xiàn)程完全結(jié)束之后,下一次調(diào)用 schedule 的時(shí)候釋放。
問(wèn)題:切換線(xiàn)程的時(shí)候, longjmp 不會(huì)恢復(fù)通用寄存器的值,因此要么函數(shù)內(nèi)的局部變量都加上 volatile ,要么在 setjmp 之前手動(dòng)保存, longjmp 之后手動(dòng)恢復(fù)(可以在庫(kù)的實(shí)現(xiàn)方完成,但是會(huì)增大不可移植的面積,現(xiàn)在暫不考慮加入)。
代碼:
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
// 測(cè)試代碼
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 2007-03-16 16:33
shifan3 閱讀(3314)
評(píng)論(4) 編輯 收藏 引用 所屬分類(lèi):
C++