平台 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
何克勤 阅读(1076)
评论(1) 编辑 收藏 所属分类:
Linux 多线程