问个protothread问题
#define PT_END(pt) LC_END((pt)->lc); PT_YIELD_FLAG = 0; \PT_INIT(pt); return PT_ENDED; }
#define PT_WAIT_UNTIL(pt, condition) \
do { \
LC_SET((pt)->lc); \
if(!(condition)) { \
return PT_WAITING; \
} \
} while(0)
---------------------------------------以上是源码
我想提2个问题:
1.PT_YIELD_FLAG = 0; 这句好像没有任何用处,它是局部变量,线程退出后自动销毁,干么给他赋值0,再退出销毁呢?
2.第二个宏定义中do{}while(0)这种结构貌似可以不要,作者为什么这样写呢? 1.PT_YIELD_FLAG = 0; 这句好像没有任何用处,它是局部变量,线程退出后自动销毁,干么给他赋值0,再退出销毁呢?
---------------------------------------------------------------------------------
PT_YIELD_FLAG貌似作为thread等待子thread用的。
2.第二个宏定义中do{}while(0)这种结构貌似可以不要,作者为什么这样写呢?
do{}while(0)能把多个语句合成一个语句,并且还必须需要后面的; 1.
PT_YIELD_FLAG是局部的(初始化为1),这个变量在调用PT_YIELD*()时会被置0,然后将lc指向下一行,最后由这句
if(PT_YIELD_FLAG == 0) { return 1; } // --- (1)
来结束。
这样,当下次恢复的时候,PT_YIELD_FLAG首先被初始化为1,然后跳到(1)行
由于不满足条件,使之可以继续执行。
2.
假设某人这样写:
if (xxx)
PT_WAIT_UNTIL(xxx);
不加do { }while(0), 你看看展开后会造成什么后果 这样,当下次恢复的时候,PT_YIELD_FLAG首先被初始化为1,然后跳到(1)行
由于不满足条件,使之可以继续执行。
-----------------------------------------------------------------------
下次重新恢复的时候,因为PT_BEGIN每次都执行,实际上重新定义了一个局部变量PT_YIELD_FLAG,PT_END退出时,已经吧PT_YIELD_FLAG这个栈上的变量销毁了,下次执行PT_BEGIN时,PT_YIELD_FLAG在栈上的位置可能已经发生了变化,所以二者名字相同,其实不是一个变量,它是局部变量,线程退出后自动销毁,干么给他赋值0,再退出销毁呢?
do { }while(0), 那个,theophilus 说的很有道理,那么可以支架{},不加do和while(0)了。。 理论上确实是不需要的,PT_YIELD_FLAG只是一个HACK.
你需要仔细看看宏定义,另外,如果你用gcc的话,可以用 gcc 的 -E -P 来输出展开宏之后的代码,方便分析
比如下例:
#include "pt.h"
static PT_THREAD(blah(struct pt *pt))
{
static int delay;
PT_BEGIN(pt);
for(delay = 1234; delay > 0; delay -= 1) {
// do something
// ...
// NOTE: Yield here
PT_YIELD(pt);
}
PT_END(pt);
}
展开后:
typedef unsigned short lc_t;
struct pt {
lc_t lc;
};
static char blah(struct pt *pt)
{
static int delay;
{ char PT_YIELD_FLAG = 1; switch((pt)->lc) { case 0:; // 这里先让PT_YIELD_FLAG = 1, 再执行跳转
for(delay = 1234; delay > 0; delay -= 1) {
do { PT_YIELD_FLAG = 0; (pt)->lc = 13; case 13:; if(PT_YIELD_FLAG == 0) { return 1; } } while(0); // 注意这一行
}
}; PT_YIELD_FLAG = 0; (pt)->lc = 0;; return 3; };
}
主要注意红色这一行,"(pt)->lc = 13" 和 "case 13:",你要分析一下两次执行blah()会发生什么情况。
其实有办法让 (pt)->lc 等于跳过 "return 1" 下面一句的行标,PT_YIELD_FLAG 就完全不需要了,只是宏定义起来不会优雅。 回复【3楼】jishanlaike阿弱
这样,当下次恢复的时候,pt_yield_flag首先被初始化为1,然后跳到(1)行
由于不满足条件,使之可以继续执行。
-----------------------------------------------------------------------
下次重新恢复的时候,因为pt_begin每次都执行,实际上重新定义了一个局部变量pt_yield_flag,pt_end退出时,已经吧pt_yield_flag这个栈上的变量销毁了,下次执行pt_begin时,pt_yield_flag在栈上的位置可能已经发生了变化,所以二者名字相同,其实不是一个变量,它是局部变量,线程退出后自动销毁,干么给他赋值0,再退出销毁呢?
do { }while(0), 那个,theophilus 说的很有道理,那么可以支架{},不加do和while(0)了。。
-----------------------------------------------------------------------
不要直接用 {}
比如
#define XXX() { /* ... */ }
if (xxx)
XXX();
else
one();
展开后, '}'后面, else前面会多一个分号,照样出错。 theophilus:非常感谢!
static char blah(struct pt *pt)
{
static int delay;
{ char PT_YIELD_FLAG = 1; switch((pt)->lc) { case 0:;
for(delay = 1234; delay > 0; delay -= 1) {
do { PT_YIELD_FLAG = 0; (pt)->lc = 13; case 13:; if(PT_YIELD_FLAG == 0) { return 1; } } while(0);
}
}; PT_YIELD_FLAG = 0; (pt)->lc = 0;; return 3; }; // 我的意思是:这行的PT_YIELD_FLAG = 0;好像没有任何用处,可以省略?
} 这里是没有用。
页:
[1]