Task Control Interfaces

Task Control Interfaces

Scheduler locking interfaces

调度程序锁定接口。这种非标准接口是用于启用和禁用占先式和测试占先式目前启用。占先式优先级是32的一种中断相应方式。

sched_lock
int sched_lock(void);

这个函数禁用添加新任务。任务调用这个函数后将会是唯一任务。

sched_unlock

这个函数衰减抢占锁计数。通常这是搭配sched_lock()。解锁抢占有时需要多次调用sched_unlock()由于之前也多次调用sched_lock()。当lockCount递减为零,任何任务都有资格来抢占当前任务执行。这里和我理解的不一样,我以为是前一个函数将当前任务锁定为唯一任务,唯一任务是个什么意思,还有待试验中发现。

sched_lockcount

这个函数返回lockCount的当前值。如果为零,抢占启用;如果非零,这个值表明sched_lock()被称为执行线程。

(顺便这里说一下上一次的时间片问题,回显的tv_sec: 0为0而tv_nsec: 200000000 值这么大的原因。时间片就是系统分给实时进程的运行时间,一旦时间片用完,那么进程将被暂停,放到FIFO队列最后面等待下一次调度。sec自然就是秒,而nsec自然就是纳秒,因为在sched_rr_get_interval 内将sec赋值的语句是一个除法,结果是一个小数,而tv_sec的类型不是一个浮点型,故为0。)

Task synchronization interfaces

等待终止子任务。

waitpid
ipid_t waitpid(pid_t pid, int *stat_loc, int options);

这个看起来还是有点复杂的。首先这个函数涉及到配置选项 CONFIG_SCHED_HAVE_PARENT 。如果定义CONFIG_SCHED_HAVE_PARENT waitpid()将更符合规范。
当该配置未开启时,waitpid()只支持等待任何任务完成执行。
当该配置开启时,waitpid() 将使用 SIGCHLD (这个貌似很厉害的样子)以达到等待任何进程。

pid 的情况有以下几种情况:

pid 结果
pid < (pid_t) -1 取绝对值
pid = (pid_t) -1 等待知道任意一个子进程返回
pid = 0 等待于调用函数的子进程组内的所有子进程
pid > 0 等待制定 pid 子进程

options的值有以下几种情况:

options 在以下情况下返回或也会返回
WCONTINUED 等待的已停止但还未报道的子进程又被其他功能继续时
WNOHANG 没有已经退出的子进程
WUNTRACED 指定的子进程已经退出但还未被报道

这里比较复杂,实际使用中碰到的时候再说

waitid

#ifdef CONFIG_SCHED_HAVE_PARENT
int waitid(idtype_t idtype, id_t id, FAR siginfo_t *info, int options);
#endif

不配置CONFIG_SCHED_HAVE_PARENT 将不会有这个函数。而且作者写这个文档时这个 东西还没不完整。如果定义CONFIG_SCHED_HAVE_PARENT waitid()将更符合规范。
waitid仅仅支持等待一个特定的子任务。
这里先说明一下 pid 和 tid :

  • pid(Process Identification) 进程识别号
  • tid(Thread Identification) 线程识别号

总的来说,pid是指进程的。tid是指线程的。pid是唯一的,但是tid只是在在同一程下是唯一的。

idtype 意义
P_PID waitid()将等待pid为id的子进程
P_PGID waitid()将等待pgid为id的进程组内所有的子进程。
P_ALL waitid()将等待任何子进程并且忽略id

options 参数表:

idtype 意义
WEXITED 等待已终止的子进程
WSTOPPED 等待那些被因接收到信号而暂停的子进程
WCONTINUES 等待那些已经停止了但是又被继续的子进程
WNOHANG 如果没有子进程需要等待,那么立即返回
WNOWAIT 返回任务的状态改变信息后,还能在之后继续获取该状态信息

wait

Task Exit Hooks

好长一段,懒得看了。直接翻译:atexit()和on_exit()可以使用注册回调函数,当一个任务组执行终止。任务组的功能模拟是一个过程:这是一组由主要任务线程和所有pthreads的主要任务创建的线程或者其他的任务broup pthreads。任务组的成员共享某些资源等环境变量,文件描述符,文件流、套接字、pthread键和开放的消息队列。

atexit

int atexit(void (*func)(void));

使用该函数注册结束前执行的空函数。

on_exit

int on_exit(CODE void (*func)(int, FAR void *), FAR void *arg);

使用该函数注册结束前执行的任务。

Parent and Child Tasks

任务同步接口“历史上?”依赖父进程和子进程之间的关系的任务。但默认的,NuttX不使用任何父/子进程知识。然而,有三个重要的配置选项,可以改变这种情况。

CONFIG_SCHED_HAVE_PARENT

如果这个设置定义,它将使NuttX记得父任务新创的每个子任务的任务ID。这种它能支持使一些额外的特性(如SIGCHLD)和修改其他接口的行为。例如,它使waitpid()更标准完成通过限制我等的那个任务的调用者。

CONFIG_SCHED_CHILD_STATUS

如果这个选项被选中时,那么子进程退出后其退出状态标志将被保留。没有这个设置 wait()waitpid()waitid() 可能会失败。

CONFIG_PREALLOC_CHILDSTATUS

为了防止失控的子进程状态分配和提高分配性能,子任务退出状态结构在系统启动时预先分配。此设置确定子进程的数量状态结构,将预先分配。如果这个设置没有定义或定义为零值为2 X MAX_TASKS使用。

又到了开始测试的时候了。

任务控制接口实验

按照我的理解先测试第一个。将 hello_task 锁住,再添加其他任务。代码:(顺便说一下我发现这个ifdef-endif很好用,既能保存之前的代码,而且还能轻松地使用define启用)
这里先停一下,任务的锁定效果并不好,不知道哪里出了问题。之前有个让任务让出CPU的函数也是这样。输出结果丝毫不受影响。搞得我都不想再测试任务了。下一个解锁的也跳过。

以下的 任务不是必须配置 CONFIG_SCHED_HAVE_PARENT ,路径:-> RTOS Features -> Tasks and Scheduling -> Support parent/child task relationships 先不配置,测试后再配置进行比对。

(前天的测试一点都不理想,关于 waitpid ,昨天刚好赶上DOTA2的7.0更新,大圣简直了,出场率100%,玩了一下午,一天都没有看代码。)

今天测试有点意外, waitpid 突然又能用了。这让我喜出望外。测试代码宏定义段:(全部代码在最后面)

#define Started_print_hello
#define Wait_print_hello_with_waitpid
#define Print_Hello_World

测试结果:

nsh> hello_task 5
hello_task: Started print_hello at PID=9
print_hello: Hello 0
print_hello: Hello 1
print_hello: Hello 2
print_hello: Hello 3
print_hello: Hello 4
hello_task: Waiting print_hello success
hello_task: Hello World 0
hello_task: Hello World 1
hello_task: Hello World 2
hello_task: Hello World 3
hello_task: Hello World 4
nsh>

效果很理想,完全达到预期。
切回去测试之前的代码,果然 lock 的不工作问题也解决了。代码宏定义段改为:

#define Started_print_hello
#define Lock_hello_task_with_sched_lock
#define Print_Hello_World

结果和上次实验的结果一样。
再来一个waitid。
首先在config里启动该选项。
-> RTOS Features -> Tasks and Scheduling -> Support parent/child task relationships
宏定义段:

#define Started_print_hello
#define Wait_print_hello_with_waitid
#define Print_Hello_World

达到相同的效果。

wait() 寻找到该代码的定义段时发现:

pid_t wait(FAR int *stat_loc) {return waitpid((pid_t) -1, stat_loc, 0);
}

这不就是waitpid() 的等待所有子进程的功能么!
我就再开一个子进程print_world,并且输出的的是print_hello 的两倍。之后发现结果是当其中一个 print_hello 结束后主进程就停止等待了,所以,我重新阅读了文档,发现之前有个小错误,waitpid(-1,...)的功能是等待所有子进程直到有任意一个子进程结束,并不是等待所有。下面一个实验当然就是waitpid(0,...)
结果,出现了错误:

hello_task: ERROR: Failed to all child task: No child processes

看样子之前的问题又暴露出来了:由进程创建的进程是不是子进程。
查了一些资料,结果是,子进程(只能?)由vfork 创建。
之前写的例子直接搬过来。重新整理代码,结果是无论如何我都不能让父进程先于子进程。查找 vfork 的代码,并没有找到,这就很诡异了。但是在这里,我找到了task_vforkstart这个函数。这个函数内有这样一段代码:

    /* Get the assigned pid before we start the task */pid = (int) child->cmn.pid;/* Activate the task */ret = task_activate((FAR struct tcb_s *) child);if (ret < OK) {task_vforkabort(child, -ret);
        return ERROR;}/* Since the child task has the same priority as the parent task, it is* now ready to run, but has not yet ran.  It is a requirement that* the parent environment be stable while vfork runs; the child thread* is still dependent on things in the parent thread... like the pointers* into parent thread's stack which will still appear in the child's* registers and environment.** We do not have SIG_CHILD, so we have to do some silly things here.* The simplest way to make sure that the child thread runs to completion* is simply to yield here.  Since the child can only do exit() or* execv/l(), that should be all that is needed.** Hmmm.. this is probably not sufficient.  What if we are running* SCHED_RR?  What if the child thread is suspended and rescheduled* after the parent thread again?*//* We can also exploit a bug in the execv() implementation:  The PID* of the task exec'ed by the child will not be the same as the PID of* the child task.  Therefore, waitpid() on the child task's PID will* accomplish what we need to do.*/rc = 0;(void) waitpid(pid, &rc, 0);
#endif
return pid;

这样看来,由于没有SIG_CHILD,所以在子进程开始之前,就已经处于 waitpid 状态,而waitpid(pid, &rc, 0)中的pid在上面就是由child->cmn.pid赋值的,总的来说就是父进程在等待子进程先于父进程结束。难怪子进程先于父进程而不是两个进程一起运行,当然,父进程先于子进程的话,父进程一结束,那子进程不久崩溃了么,父进程先于子进程肯定是不行的。除非有这里提到的SIG_CHILD。这个等待所有子进程的就算是完成了。当然只有一个子进程需要等待的,如果在子进程中再调用一次 vfork 便会出现嵌套的 waitpid 看样子想要让父进程等待很多子进程还远着呢。

下一个就是两个任务在执行完成前调用其他函数的函数。
使用atexit()之前还需要在configure中开启CONFIG_SCHED_ATEXIT,路径 -> RTOS Features -> RTOS hooks -> Enable atexit() API然后设定数量上限。代码宏定义部分:

#define atexit_test

结果不言而喻。但是另一个出了问题。完全没有运行。其定义令我费解:

int on_exit(CODE void (*func)(int, FAR void *), FAR void *arg);

…就看在我心情不错的份上先放它一马。本章结束。最后,所有代码:

#include <sched.h>
#include <nuttx/config.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/wait.h>
#include <stdlib.h>/********************************************************** Pre-processor Definitions
*********************************************************/
//#define here
/********************************************************** Private Functions
*********************************************************/
#if defined(Started_print_hello)||defined(Started_print_world)\||defined(Print_Hello_World)||defined(on_exit_test)
int str2num(const char *s) {int rt = 0;while (*s >= '0' && *s <= '9') {rt = rt * 10 + (*s - '0');s++;}return rt;
}
#endif#ifdef Started_print_hello
int print_hello(int argc, char *argv[]) {int i;int a = str2num(argv[1]);for (i = 0; i < a; ++i) {sched_yield();printf("%s: Hello %d\n", argv[0], i);}exit(EXIT_SUCCESS);
}
#endif#ifdef Started_print_world
int print_world(int argc, char *argv[]) {int i;int a = str2num(argv[1]);for (i = 0; i < (a * 2); ++i) {printf("%s: World %d\n", argv[0], i);}exit(EXIT_SUCCESS);
}
#endif#ifdef atexit_test
void fun(void) {printf("fun\n");
}
#endif/********************************************************** Public Functions
*********************************************************//********************************************************** hello_task
*********************************************************/
int hello_task_main(int argc, char *argv[]) {int ret = 0;pid_t hello_task_pid;hello_task_pid = getpid();#ifdef Started_print_hellopid_t print_hello_pid;print_hello_pid = task_create("print_hello",SCHED_PRIORITY_DEFAULT, 2048, print_hello, &argv[1]);if (print_hello_pid < 0) {int errcode = errno;printf("%s: ERROR: Failed to start print_hello: %s\n", argv[0],strerror(errcode));exit(EXIT_FAILURE);} elseprintf("%s: Started print_hello at PID=%d\n", argv[0], print_hello_pid);
#endif#ifdef Started_print_worldpid_t print_world_pid;print_world_pid = task_create("print_world",SCHED_PRIORITY_DEFAULT, 2048, print_world, &argv[1]);if (print_world_pid < 0) {int errcode = errno;printf("%s: ERROR: Failed to start print_world: %d\n", argv[0],strerror(errcode));exit(EXIT_FAILURE);} elseprintf("%s: Started print_world at PID=%d\n", argv[0], print_world_pid);
#endif#ifdef Wait_child_task_with_waitpidret = waitpid(print_hello_pid, NULL, 0);if (ret == ((pid_t) -1)) {int errcode = errno;printf("%s: ERROR: Failed to wait print_hello: %s\n", argv[0],strerror(errcode));exit(EXIT_FAILURE);} elseprintf("%s: Waiting print_hello success\n", argv[0]);
#endif#ifdef Wait_child_task_with_waitidret = waitid(P_PID, print_hello_pid, NULL, 0);if (ret == ((pid_t) -1)) {int errcode = errno;printf("%s: ERROR: Failed to wait print_hello: %s\n", argv[0],strerror(errcode));exit(EXIT_FAILURE);} elseprintf("%s: Waiting print_hello success\n", argv[0]);
#endif#ifdef Wait_child_task_with_waitret = wait(NULL);if (ret == ((pid_t) -1)) {int errcode = errno;printf("%s: ERROR: Failed to wait child task: %s\n", argv[0],strerror(errcode));exit(EXIT_FAILURE);} elseprintf("%s: Waiting child task success\n", argv[0]);
#endif#ifdef Lock_hello_task_with_sched_lockprintf("%s: Lock Count: %d\n", argv[0], sched_lockcount());ret = sched_lock();if (ret) {printf("%s: Lock myself Fail\n", argv[0]);} else {printf("%s: Lock myself Success\n", argv[0]);printf("%s: Lock Count: %d\n", argv[0], sched_lockcount());}
#endif#ifdef Print_Hello_World{int i;int a = str2num(argv[1]);if (a == 0)printf("%s: There is nothing to say%d\n", argv[0], i);elsefor (i = 0; i < a; ++i) {printf("%s: Hello World %d\n", argv[0], i);}}
#endif#ifdef atexit_testatexit(fun);
#endifexit(EXIT_SUCCESS);
}

NuttX的学习笔记 9相关推荐

  1. Nuttx系统学习笔记(三)——使用Nuttx操作STM32F429外设

    在上一篇,我们已经学会了如何将Nuttx进行烧录,以及学会了如何部署这个操作系统,接下来我们就要使用这个操作系统来实现我们对嵌入式设备的控制,当然也是从点灯开始的.这个基于Posix架构的操作系统使用 ...

  2. NuttX的学习笔记 13

    2.6 Clocks and Timers 这部分是时钟与定时器,ostest里面并没有发现相关东西,在例子里找到了timer,在configure里开启这个例子. 查看这个例子的Kconfig文件, ...

  3. NuttX的学习笔记 12

    #2.5 Counting Semaphore Interfaces Semaphores. Semaphores are the basis for synchronization and mutu ...

  4. NuttX的学习笔记 14

    下面来分析timer这个例子吧. int timer_main(int argc, char *argv[]) {struct timer_notify_s notify;struct sigacti ...

  5. NuttX的学习笔记 11

    板子可以跑NuttX了,继续研究ostest 之前是在讲消息队列的,那么这节就把ostest里面相关消息队列的代码分析一遍. 先从ostest_main()开始. apps\examples\oste ...

  6. NuttX的学习笔记 8

    好了,新开一篇继续新的内容 Task Scheduling Interfaces sched_setparam sched_getparam sched_setscheduler sched_gets ...

  7. NuttX的学习笔记 2

    README文档目录的第二部分 Configuring NuttX Instantiating "Canned" Configurations Refreshing Configu ...

  8. MavSDKMavros学习笔记

    MavSDK&Mavros学习笔记 Introduction · MAVSDK Guide (mavlink.io) GitHub - mavlink/MAVSDK源码 C++ · MAVSD ...

  9. PX4/APM/飞控的学习笔记前言-Cxm

    开始了 开始了 终于有时间可以学习飞控了 此文章是用来当目录,我会持续更新我的学习之旅,希望能对各位有所帮助 如果有错误的地方还请各位前辈指点. 此帖持续更新后续内容 其实从21年的一月就开始学习飞控 ...

最新文章

  1. cout 输出指定位数,不足补0
  2. java 删除二进制内容_从二进制矩阵中仅删除一个元素的行/列
  3. python创建数据库表空间_7.自动化监控多个Oracle表空间
  4. 那位标榜技术驱动的开发者去哪了?
  5. android中屏幕宽高显示不全,Android 获取屏幕宽度跟高度
  6. 软件中的1、同步调用;2、回调;3、异步调用
  7. Android 出现警告Exported service does not require permission
  8. Net设计模式实例之中介者模式(Mediator Pattern)
  9. python装饰器理解_如何理解Python装饰器?
  10. python代码评测结果tle_比比谁的代码短:TLE测试赛结束
  11. The field file exceeds its maximum permitted size of 1048576 bytes.
  12. java ppt转图片 失真_java转换ppt,ppt转成图片,获取备注,获取文本
  13. DID 去中心化数字身份
  14. 《梦幻西游》手游服务器如何实现200万玩家同时在线?(技术篇)
  15. 银行不良贷款很大一部分是诈骗的结果:CAG
  16. qq2009 好像和金山词霸屏幕取词有冲突
  17. 计算机自定义桌面设置在哪里设置,桌面显示日历设置方法
  18. Navicat Premium的下载及安装
  19. php notice undefined variable,解决PHP提示Notice: Undefined variable的办法
  20. 微距摄影,如何用单反相机拍好昆虫照片

热门文章

  1. excel手机版_微软开发于手机端的办公软件!
  2. 云服务器怎么设置成代理服务器?
  3. 胭脂茉莉点评推荐上海大学法院李本教授诗集《秋月曲》诗歌6首
  4. 2022年推土机司机(建筑特殊工种)考试题库及推土机司机(建筑特殊工种)考试技巧
  5. 机械手表,石英手表,智能手表怎么选最好,哪种更适合佩戴?
  6. 贷款违约行为的ANOVA分析——关于不同抽样方法得到不同结论的分析
  7. python3.6.国家政策文本分析代码
  8. 大学的终结,终结了什么???
  9. Linux下堆漏洞利用(off-by-one)
  10. ABAP 使用Smartforms发送HTML邮件