posts - 134,comments - 22,trackbacks - 0

          平臺 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 何克勤 閱讀(1087) 評論(1)  編輯  收藏 所屬分類: Linux 多線程

          FeedBack:
          # re: 用戶態非搶占式線程庫實現 (轉)
          2011-10-31 10:29 | GG大嬸
          那POXIS的用戶態多線程也是這么實現的嗎?  回復  更多評論
            
          主站蜘蛛池模板: 靖江市| 抚远县| 汕头市| 乐平市| 长治市| 招远市| 沙田区| 临澧县| 永吉县| 遵义市| 镇沅| 乌审旗| 衡山县| 天水市| 奇台县| 康保县| 祁连县| 永寿县| 孟津县| 平潭县| 太谷县| 米泉市| 田林县| 三明市| 乌兰察布市| 天柱县| 兴仁县| 平阳县| 榆林市| 靖江市| 绿春县| 扎兰屯市| 青海省| 苏尼特右旗| 名山县| 民勤县| 崇礼县| 涿州市| 韶关市| 武鸣县| 天等县|