本帖最后由 hotpower 于 2011-5-23 19:04 编辑
John Lee 21:59:29
今天夜话讨论LOOK的任务管理。
一般RTOS的任务都是由一个称为TCB(任务控制块)的数据结构来表示的。
这一点LOOK也不例外。
既然LOOK是基于C++的RTOS,自然,这个TCB就要用一个类来表示才优雅。
murex 22:01:54
每个任务都有个TCB吧
John Lee 22:03:31
这个类名字是task_t
class task_t : public idle_task_t {
public:
bool wakeup() __OPT_ATTR__;
bool do_wakeup();
protected:
task_t() __OPT_ATTR__;
protected:
void on_signal(void* addr, uintptr_t signal);
private:
virtual void routine() = 0;
};
不要被吓到。
只需注意一点,这个类(就是TCB)中没有任何数据。
全是函数。
那么TCB的数据怎么表示?
回复
murex 22:08:14
实例?
天天天蓝 22:08:27
virtual void routine() = 0;
函数返回值?
murex 22:08:43
纯虚函数
没有返回值
天天天蓝 22:08:58
怎么赋值0
murex 22:09:15
表示纯虚函数
John Lee 22:09:26
LOOK是一个可多选择调度算法的RTOS, 例如:固定优先级算法(fp)
它的任务TCB里面就应该有优先级数据。
而基于协作、时间片等调度算法的任务,应该有一个链表节点在tcb中。
就是说,TCB中的某些数据是给调度器用的。
随着调度器的不同,TCB的数据也有所变化。
murex 22:12:38
sched_t这个是调度器类吧
John Lee 22:12:45
对
但我们知道,类(class)或者结构(struct),一旦定义好之后,是不能改变其内部成员的。
那么,定义一个包含所有调度算法都用到的TCB?
murex 22:14:57
调度算**不会随时变动的?
John Lee 22:15:02
可行是可行的,但太臃肿了。
不会
一个具体项目只能选择一个调度算法。
murex 22:15:27
那就可以通过#ifdef来编译
选择相应的调度算法了
John Lee 22:16:13
是可以的。
但有个问题。
某些调度算法的TCB完全包含包含另一个算法的TCB,怎么办?
murex 22:17:52
那那是有些麻烦,不停判断也不是个办法
John Lee 22:18:26
struct TCB1 {
member A,B,C;
};
struct TCB2 {
member A,B,C;
member D,E,F;
};
这个是C的表示方法。
或者:
struct TCB2 {
struct TCB1 tcb1;
member D,E,F;
};
murex 22:19:28
TCB2就包含了TCB1
John Lee 22:19:36
对
这时,就不能用#ifdef 条件编译了。
murex 22:20:11
嗯,是的
murex 22:21:35
冷、忍、能者 22:22:04
还不太懂,先听你们说
murex 22:22:38
其实我也跟你们一样的
我就没玩过os
学习芯唐 22:23:01
难啊
murex 22:23:09
只会8位单片机
也就跟菜农才开始学M0
我想你们都比我要好的了
有什么问题就问,老师是会帮我们找到根结的,让我们吃透为止
冷、忍、能者 22:25:01
刚编译了下,Lee_DS18B20.cpp
编译不过
murex 22:25:28
下载我弄的那个模版
John Lee 22:25:37
好,提问时间。
John Lee 22:26:00
编译不过,菜地解决一下。
murex 22:26:10
嗯,好
冷、忍、能者 22:26:29
LOOK+PROJECT这个文件包
murex 22:27:15
可能是的
murex 22:27:18
进去给我看下
John Lee 22:27:28
这个问题,你们在群里聊,其他人有问题么?
murex 22:27:56
是这个,问这样的问题到群里,不在这里
John Lee 22:28:30
好,大家不吭声,就是没问题了。
冷、忍、能者 22:28:49
对上面说的暂时没有
John Lee 22:28:59
那么我们创建任务实例的时候,是不是要根据TCB类型的不同而不同呢?
John Lee 22:30:20
TCB1 tcbA;
TCB1 tcbB;
...
万一写成这样了:
TCB1 tcbA;
TCB2 tcbB;
难道说,要同时使用两种调度算法?
murex 22:32:01
这个不是一般不容许呀
John Lee 22:32:35
各位,有没有比较令人满意的方案?
怎么个不容许?
murex 22:33:16
John Lee 22:34:00
是的,只能有一个调度算法。
murex 22:34:22
如果TCB2包含TCB1,那就都用TCB2好了
John Lee 22:34:40
但用户这样写:
struct TCB1 tcbA;
struct TCB2 tcbB;
编译有问题么?
murex 22:34:52
那应该没有吧
John Lee 22:35:09
对啊,语法上允许的啊。
所以,这个方案不能令人满意。
最好的效果是,统一用一个名称定义。
有点难?
murex 22:37:14
用namespace
John Lee 22:37:44
这个时候,就显示出C++的威力了。
murex 22:37:41
把这两个都定义进去
John Lee 22:40:49
namespace co { // 协作式空间
class task_t { // 协作任务类定义(TCB)
...
};
}
namespace rr { // 时间片轮转空间
class task_t : public co::task_t { // 时间片任务类,继承了协作任务类
...
};
}
要使用统一的任务类TCB名称,可以用“名空间”分隔。
并且,一个名空间中的类,可以继承另外一个名空间的类。
如上面的代码,任务类都叫task_t,但各属于 co 和 rr 空间的。
并且 rr 空间的 task_t 继承了 co 空间的 task_t。
那么 rr 空间的 task_t 就包含了 co 空间 task_t 的成员。
就像 TCB2 包含了 TCB1 一样。
用户使用时,只需要在程序开头,写一个 using namespace co; 或者 using namespace rr;
然后,在后面的程序中就可以直接使用 task_t 来创建实例了。
task_t taskA;
task_t taskB;
murex 22:47:37
这就简单了
John Lee 22:48:28
如果我们使用了 using namespace rr; 那么 co 空间的 task_t 是不会暴露给用户的。
所以用户永远不可能搞错(除非故意)。
task_t taskA, taskB; // 这两个实例,只可能是 rr 空间的 task_t
murex 22:50:41
没法直接定义co空间的task_t吧
John Lee 22:51:27
语法可以,这就是“故意”了。
可以这样写:co::task_t taskC;
murex 22:51:37
只能是rr空间的,访问是可以访问到的co空间的task_t
嗯,这好像是可以了
John Lee 22:52:37
但这明显是故意了,与:
TCB1 tcbA;
....
...
TCB2 tcbB;
有本质区别。
后面的方法,很容易“过失”犯错。
但 co::task_t taskC; 就是明显故意捣乱了。
murex 22:53:41
现在的话就只要用task_t即可了
John Lee 22:53:49
对
murex 22:54:16
那倒是简单多了,不用去记到底用TCB1,还是TCB2了
John Lee 22:54:48
这就是 C++ 比 C 优雅的地方之一。
murex 22:55:00
这个名字空间的确有意思
John Lee 22:55:35
尽量使用编译语法去约束使用者,减少犯错的机会。
murex 22:56:29
嗯,好处不少,靠眼睛去发现,还不如靠编译器去发现问题直接
John Lee 22:56:34
而不是像 C 那样,强迫使用者去**一些很相似,但有明显区别的名字或概念。
有了 C++ 的 namespace 支持,LOOK的任务TCB(任务类task_t),可以跟随调度算法的不同,而只保留有用的成员。
murex 22:59:14
那就相当于可以同时支持多种调度算法了
John Lee 23:00:00
不能说同时!
murex 23:00:12
那应该说在同一个项目里
支持多种调度算法
John Lee 23:00:54
反正不是同时的意思。
murex 23:01:11
嗯
John Lee 23:02:01
Any question ?
冷、忍、能者 23:03:07
能不能解释下namespace
John Lee 23:03:34
好,今天就到这里吧。如果大家还有兴趣,以后可以早一点时间,多讨论一些内容。
namespace?
namespace是C++的关键字。
murex 23:04:48
就是把一堆名字放在一起,统一定义一个名字,好像有点类似这样
John Lee 23:05:09
用于区分某些“名字”。
namespace的出现,是由于随着项目规模的增大,名字冲突越来越严重。
例如:在我编写程序的一个模块中,我把一个类(或结构,全局变量等等),命名为 abc;
而别的同事的另一个模块中,也有一个名字为abc的。
在链接时,可能发生名字冲突。
murex 23:08:45
肯定会的了
John Lee 23:09:11
规模越大,冲突可能性越高。
为了解决这一问题,C++就引入了“名字空间”这一概念。
把一些有关的定义,全局数据等,归入一个“名空间”中。
那么别人的模块中的定义,数据等也照此办理。
那么就会大大降低冲突的几率。
murex 23:13:25
那就是不能同时使用using namespace
不然还是会造成同名的了
John Lee 23:13:40
可以
using namespace co;
using namespace rr;
语法上允许同时使用。
murex 23:14:29
那task_t就不知道哪个了
John Lee 23:14:43
但在实例化时,编译器会报错。
murex 23:14:47
嗯,那就没问题了
相当于帮你找出了同名的问题了
John Lee 23:15:12
“task_t 名称歧义”
就是说,编译器搞不清楚,你到底要哪个 task_t 类来实例化。
murex 23:16:53
嗯,那是的了
John Lee 23:17:14
Any question ?
回复
John Lee 23:18:13
讨论结束。 |