在此篇中,我会向大家展示如何创建 LOOK 系统中的任务,我将使用上一篇的“示例 1”来做讲解。在示例 1 中,有些语句是无关紧要的,如: __attribute__ ((always_inline)) 等等,你可以先忽略掉这些。
在 LOOK 系统中,除了系统初始化外的所有工作都应该放在任务(task)里来做(其它操作系统也是如此)。那么首先遇到的问题就是:在 LOOK 中如何创建一个任务并让它运转起来。
创建一个任务分为三步:
一、声明(declare)和定义(define)任务类 在 LOOK 系统中,任务是以一个 C++ 类来表达的(与其它操作系统的任务控制块概念相当)。并且必须从 task_t 类或 task_t 类的派生类继承,task_t 类是 LOOK 系统声明的一个抽象类。在示例 1 中,我们声明了两个任务(类):task1_t 和 task2_t。
task1_t 的声明(task2_t 也是同样的): class task1_t : public task_t // 此 C++ 语法表示:声明一个以 task1_t 为名称的类,该类从 task_t 中派生,或者说,该类继承 task_t 类。 然后就需要声明该类的成员了,有两个成员是必须声明的:
1、构造函数 task1_t (size_t stack_size) __attribute__ ((always_inline));
任务类的构造函数必须声明的理由是:它的基类 task_t,没有缺省的构造函数。事实上,task_t 类的构造函数如下所示: task_t (size_t stack_size, void* arg = 0);
task_t 类的构造函数需要两个参数,第一个:该任务所占的 RAM 空间大小,这个必须由它的子类——任务 (task1_t) 类构造函数来传递(见后)。第二个:任务函数的参数,类似于 uC/OS,eCos 之类的操作系统,这个参数可以省略。 而任务类的构造函数的参数就全由编程者自己考虑了,省略也可以,只要传给 task_t 一个合适的 stack_size 值就可以了。构造函数在此还必须初始化类成员 seam(见后)。
2、任务函数 virtual void process (void* arg);
这个就是任务的工作函数了,这个是由 task_t 类声明的纯虚函数,所以 task_t 是个抽象类,不能实例化(定义类对象),这些概念都是 C++ 的,其实不用我在这里废话了。void* arg 参数就是 task_t 构造函数的第二个参数传递来的。 至于工作函数里应该怎么定义(怎么写),那就是你说了算。在示例 1 中,先创建了 task2,然后进入任务主循环。
其它的成员的声明: 1、sema_t sema; 信号灯。sema_t 是 LOOK 系统声明的一个同步对象。sema_t 没有缺省的构造函数。所以,sema 成员的初始化也必须由 task1_t 类的构造函数来执行。sema_t 的构造函数声明: sema_t (unsigned int count);
参数 count 是提供给信号灯的初始值。信号灯的使用方法以后详细说明。
2、void notify () __attribute__ ((always_inline)); 这个函数简单地对 sema 进行 V 操作。它存在的必要仅仅是为了数据隐藏(C++ 程序设计的原则之一)。
二、创建任务类的对象(类实例化) 这里只推荐一个方法:定义一个 RAM 区,然后用 placement new 在此 RAM 区上 new 一个类对象:
task_t *new_task = new (task1) task1_t (sizeof (task1));
这里存在一个非常重要的问题:
如何确定 RAM 区的大小?
LOOK 系统设计,任务类的对象和任务栈一起被放置在用户定义的 RAM 区中,所以 RAM 区的大小由任务类的大小和任务栈的大小共同决定。对象的大小可以用 sizeof (类名) 来得到,而任务栈的大小由两部分组成:①保存任务上下文所需要的空间。这个空间大小是个固定数,在 LOOK 系统中,这个值是 19 字节。②任务调用函数的层数和各函数的局部变量大小,这个值不太好确定,但用户(基于 LOOK 系统的应用程序设计者、编程者)必须估算出一个安全的最小值。还有 LOOK 系统调用自己也需要一些空间,但非常少,不超过 10 字节。
确定好了任务栈大小后,就可以定义 RAM 区了:uint8_t task1[sizeof (task1_t) + SIZE_TASK1_STACK];SIZE_TASK1_STACK 就是用确定好的任务栈大小定义的宏。
三、任务类对象加入调度器 这个用 sched_t 类的方法 add 就可以了,sched_t 类也是 LOOK 系统声明的。add 方法的声明: static void add (task_t* task, unsigned char prio);
第一个参数是任务类对象,第二个参数是任务的优先级。
任务对象一旦加入调度器,就立刻处于就绪态。
待续...
|