随笔 - 31  文章 - 128  trackbacks - 0
<2012年12月>
2526272829301
2345678
9101112131415
16171819202122
23242526272829
303112345

常用链接

留言簿(5)

随笔分类(38)

随笔档案(31)

收藏夹(4)

College

High School

最新随笔

搜索

  •  

积分与排名

  • 积分 - 47500
  • 排名 - 396

最新评论

  • 1. re: [yc]详解link
  • 面试的时候面试官就问过我什么是编译和链接,我说编译就是把代码文件生成目标文件,链接就是把目标文件生成可执行文件,他说不对,又问我什么是动态链接,还问我预编译都做什么处理。。。都在这里找到了答案!!!!
  • --王至乾
  • 2. re: [yc]详解link
  • @刘伟
    我是说博主,不是叫你啊
  • --溪流
  • 3. re: [yc]详解link
  • 谁是石老师,我不是哈@溪流
  • --刘伟
  • 4. re: [yc]详解link
  • 石老师?我是溪流~
  • --溪流
  • 5. re: [yc]详解link
  • 期待楼主下文啊,多谢楼主了
  • --刘伟

阅读排行榜

评论排行榜

平台 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 2007-03-16 16:33 shifan3 阅读(2798) 评论(4)  编辑 收藏 引用 所属分类: C++

FeedBack:
# re: 用户态非抢占式线程库实现 2007-03-16 23:44 pluskid
哦?是在每个线程里面都要收工调用 schedule() 函数来切换线程的吗?  回复  更多评论
  
# re: 用户态非抢占式线程库实现 2007-03-17 02:52 Francis Arcanum
@pluskid
是的  回复  更多评论
  
# re: [yc]用户态非抢占式线程库实现 2007-05-08 11:25 Rhythm
我想不通……一个用来贴代码的blog系统,代码本身为啥不是等宽字体?  回复  更多评论
  
# re: [yc]用户态非抢占式线程库实现 2007-05-08 14:12 Francis Arcanum
@Rhythm
我错了,貌似是我没选择字体。。。  回复  更多评论
  

只有注册用户登录后才能发表评论。
【推荐】超50万行VC++源码: 大型组态工控、电力仿真CAD与GIS源码库
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理