ProtoThreads的抢占式调度问题

Protothreads是Adam Dunkels实现的用户级轻量级线程库。它的主页在: http://dunkels.com/adam/pt/index.html。

它使用特殊技巧的switch语句模拟了用户线程的调度原语。可以使用的用户线程数不受限制。由于简易,Protothreads线程不支持局部变量,需要避开用户的switch语句,以及不支持抢占式调度。

这里设想通过添加计数器的方法,模拟时间片,时间片到时之后,强制释放处理器,模拟通常的抢占式调度。

pt.h中, struct pt增加两个变量:
int count;
int reload;

PT_BEGIN宏,里面增加一句:
…; (pt)->count= -(pt)->reload; …

再增加2个宏:
#define PT_INIT_COUNT(pt, n) ((pt)->reload=n)
#define PT_COUNT(pt) if(++(pt)->count>=0) PT_YIELD(pt)

现在来看效果。利用原来的example-small.c例子,其中加入了 PT_COUNT,为了便于观察,主程序中再添加一句打印:

printf(“Sched on %d\n”, ++i);

/**
 * This is a very small example that shows how to use
 * protothreads. The program consists of two protothreads that wait
 * for each other to toggle a variable.
 */
~
/* We must always include pt.h in our protothreads code. */
#include "pt.h"
~
#include <stdio.h> /* For printf(). */

/* Two flags that the two protothread functions use. */
static int protothread1_flag, protothread2_flag;

/**
 * The first protothread function. A protothread function must always
 * return an integer, but must never explicitly return - returning is
 * performed inside the protothread statements.
 *
 * The protothread function is driven by the main loop further down in
 * the code.
 */
static int
protothread1(struct pt *pt)
{
    
    
static int i;
  /* A protothread function must begin with PT_BEGIN() which takes a
     pointer to a struct pt. */
  PT_BEGIN(pt);

  /* We loop forever here. */
  while(1) {
    
    
    /* Wait until the other protothread has set its flag. */
    PT_WAIT_UNTIL(pt, protothread2_flag != 0);
    printf("Protothread 1 running\n");

        for(i=0;i<20; i++) {
    
    
                printf("%d.\n", i);
                PT_COUNT(pt);
        }
    /* We then reset the other protothread's flag, and set our own
       flag so that the other protothread can run. */
    protothread2_flag = 0;
    protothread1_flag = 1;

    /* And we loop. */
  }

  /* All protothread functions must end with PT_END() which takes a
     pointer to a struct pt. */
  PT_END(pt);
}

/**
 * The second protothread function. This is almost the same as the
 * first one.
 */
static int
protothread2(struct pt *pt)
{
    
    
  PT_BEGIN(pt);

  while(1) {
    
    
    /* Let the other protothread run. */
    protothread2_flag = 1;

    /* Wait until the other protothread has set its flag. */
    PT_WAIT_UNTIL(pt, protothread1_flag != 0);
    printf("Protothread 2 running\n");

    /* We then reset the other protothread's flag. */
    protothread1_flag = 0;

    /* And we loop. */
  }
  PT_END(pt);
}

/**
 * Finally, we have the main loop. Here is where the protothreads are
 * initialized and scheduled. First, however, we define the
 * protothread state variables pt1 and pt2, which hold the state of
 * the two protothreads.
 */
static struct pt pt1, pt2;
int
main(void)
{
    
    
        int i=0;
  /* Initialize the protothread state variables with PT_INIT(). */
  PT_INIT(&pt1); PT_INIT_COUNT(&pt1, 5);
  PT_INIT(&pt2); PT_INIT_COUNT(&pt2, 5);

  /*
   * Then we schedule the two protothreads by repeatedly calling their
   * protothread functions and passing a pointer to the protothread
   * state variables as arguments.
   */
  while(1) {
    
    
        printf("Sched on %d.\n", ++i);
    protothread1(&pt1);
    protothread2(&pt2);
  }
}

编译。运行。这里摘录了运行结果的一个片断:

Sched on 181.
Protothread 2 running
Sched on 182.
Protothread 1 running
0.
1.
2.
3.
4.
Sched on 183.
5.
6.
7.
8.
9.
Sched on 184.
10.
11.
12.
13.
14.
Sched on 185.
15.
16.
17.
18.
19.
Sched on 186.
Protothread 2 running
Sched on 187.
Protothread 1 running
0.
1.
2.
3.
4.
Sched on 188.

可以看到,在线程一for循环模拟的耗时操作过程中,发生了多次调度。

Guess you like

Origin blog.csdn.net/aaasssdddd96/article/details/108062294