1.1 操作系统相关服务
ETest 提供了 Task_T Semaphore_T Mutex_T Counter_T 等类以提供操作系统相关的服务,可以实现任务调度与协同。
1.1.1 Task_T类
所在命名空间为:Kiyun::LowerComputer::Rasl::Os。这个类的对象代表在下位机中运行的任务。
| /** 系统固定头文件 / #include <Rasl/rasl.hpp> #include <DataUploader/DataUploader.hpp> #include "StaticVariable.h" #include "rasl-dpd/user.hpp" #include "UserChannels.rasi" #include "DataCollect.hpp" /* 系统固定头文件 / //用户测试代码需要新增的头文件 namespace{ using namespace Kiyun::LowerComputer; using namespace Kiyun::LowerComputer::Rasl; using namespace Kiyun::LowerComputer::Rasl::Frame; using namespace Kiyun::LowerComputer::Rasl::Device; //通道设备命名空间 using namespace Kiyun::LowerComputer::DataUploader; //数据上传命名空间 using namespace Kiyun::Channel; using namespace Kiyun::DataCollect; //数据采集接口命名空间 using namespace Dpdp; //协议命名空间 using namespace std; using namespace Rasl::Frame; using Rasl::Logging_T; using Rasl::Os::Task_T; //本地变量、本地函数声明 //Os::Semaphore_T f_exitSem; int x(0); int adder(void) { for(int i = 0; i < 100000; ++i) ++x; return 0; } } //主函数入口 int Main() { //设置全局日志属性 KYLOG_GLOBAL().severity(Logging_T::Severity_E::DEBG_e); KYLOG_SCOPE("main").tag("信号相关").tag("硬件"); KYLOG(INFO) << "Hello world, Kiyun!\n"; //可保存到日志文件 KYIO(log) << "Hello World,Kiyun!\n"; //发送到控制台 /测试代码/ vector<Task_T> tasks; for(int i = 0; i < 200; ++i) { tasks.push_back(Task_T::spawn(adder).first); } for(auto t : tasks) t.wait(); KYLOG(INFO) << "x : " << x; KYLOG_DEF(INFO).tag("单项标记"); KYLOG_USE() << "Y : " << x; //f_exitSem.wait(); return 0; } bool Exit(Os::Task_T) { //返回值为true,表示能中止正在运行的实时任务 //f_exitSem.notifyOne(); //return true; return false; //默认情况下该实时任务不能被中止 } |
|---|
1) spawn方法
函数原型:std::pair<Task_T, Error_T> spawn(const SimpleEntry_T& ent)
函数功能:启动一个任务。
参数:ent:型如 int (void*) 的函数。其参数忽略即可,正常情况应返回 0。
返回值:一个 pair 对象,first 成员是启动的 Task_T 对象,second 成员是错误情况。大多数情况下,second 成员可以安全的忽略。
2) wait方法
函数原型:void wait();
函数功能:等待任务结束。调用者任务本身阻塞,直到所 wait 的任务退出才继续运行。必须在 spawn 所返回的 Task_T 对象上使用。
3) waitFor方法
函数原型:
| Mince::LowerComputer::Rasl::Error_T waitFor( Mince::LowerComputer::Rasl::Frame::Timeout_T t ); |
|---|
函数功能:等待任务结束或超时。调用者任务本身阻塞,直到所 wait 的任务退出或者超出指定的时间才继续运行。必须在 spawn 所返回的 Task_T 对象上使用。
参数:t:超时时长。
返回值:无错误代表所等待的任务已退出,有错误代表超时。
| auto task = Task_T::spawn(someFunction); auto err = task.waitFor(5_s); if(err) KYLOG(WARN) << "任务在指定时间内未结束!"; |
|---|
1.1.2 Semaphore_T类
所在命名空间为:Kiyun::LowerComputer::Rasl::Os。
- 构造方法
函数原型:Semaphore_T()
函数功能:初始化一个Semaphore_T对象
参数:无
返回值:无
2) notifyOne
函数原型:void notifyOne()
函数功能:发送一个信号量,通知正在等待信号量的第一个线程继续执行。
参数:无
返回值:无
3) notifyAll
函数原型:void notifyAll()
函数功能:通知所有等待信号量的线程继续执行。
参数:无
返回值: 无
4) wait
函数原型:void wait()
函数功能:等待信号量。执行此方法的任务立即阻塞,直到其它任务在此信号量上调用 notify 为止。
参数:无
返回值: 无
5) waitFor
函数原型:bool waitFor(Kiyun::LowerComputer::Rasl::Frame::Timeout_T time)
函数功能:等待信号量的到来,最长等待时间为time,单位为秒。
参数:time:等待时长
返回值: true: 信号量到达;false: 超时。
1.1.3 Mutex_T类
所在命名空间为:Kiyun::LowerComputer::Rasl::Os。这个类用作互斥锁,通常用于保护那些“不可同时访问的资源”。
| #include <Rasl/rasl.hpp> namespace { using namespace std; using namespace Kiyun::LowerComputer; using namespace Rasl::Frame; using Rasl::Os::Task_T; using Rasl::Os::Mutex_T; int x = 0; Mutex_T xMut; int adder(void*) { KYLOG_SCOPE("add"); xMut.lock(); for(int i = 0; i < 100000; ++i) ++x; xMut.unlock(); KYLOG(INFO) << "加完"; return 0; } } int kiyunMain() { KYLOG_SCOPE("main"); vector<Task_T> tasks; for(int i = 0; i < 200; ++i) { tasks.push_back(Task_T::spawn(adder).first); } for(auto t : tasks) t.wait(); KYLOG(INFO) << "x : " << x; return 0; } |
|---|
1) lock 方法
函数原型:void lock();
函数功能:取得锁。如果锁已被其它任务取得,则任务立即阻塞,直到锁被释放为止。如果锁已被本任务取得,再次调用 lock,后果未定义。
参数:无
返回值:无
2) unlock 方法
函数原型:void unlock();
函数功能:释放锁。
参数:无
返回值:无
3) tryLock 方法
函数原型:bool tryLock();
函数功能:取得锁。如果锁已被其它任务取得,则返回 false,否则返回 true。如果锁已被本任务取得,再次调用本方法,后果未定义。
参数:无
返回值:true: 取锁成功;false:未取得锁。
4) Guard_T内嵌类
其构造函数以一个 Mutex_T 对象为参数,并在构造时调用其 lock 方法。在析构时调用对应 Mutex_T 对象的 unlock 方法。
| std::queue<命令_T> 队列; Mutex_T 队列锁; void 入列(const 命令_T& cmd) { MCLOG_SCOPE("入列"); { // 用花括号划定锁的保护范围 Mutex_T::Guard_T guard{队列锁}; 队列.push(cmd); } // guard 对象在此之前析构,这里不再是锁的保护范围 MCLOG(INFO) << "命令已入列。"; } |
|---|
f="">1.1.4 Counter_T类
所在命名空间为:Kiyun::LowerComputer::Rasl::Os。这个类用作计数器,用于“生产者与消费者”模式时,给资源计数。在多个生产者和/或多个消费者的场合,计数器能够保证资源计数的正确性。
| #include <Rasl/rasl.hpp> #include namespace { using namespace std; using namespace Kiyun::LowerComputer; using namespace Rasl::Frame; using Rasl::Error_T; using Rasl::Device::Com_T; using Rasl::Os::Task_T; using Rasl::Logging_T; auto com00 = Com_T::get(Com_T::Setup_T("com/0/0") .baudRate(115200) .parity(Com_T::Parity_E::NONE_e) ); auto com01 = Com_T::get(Com_T::Setup_T("com/0/1") .baudRate(115200) .parity(Com_T::Parity_E::NONE_e) ); auto com02 = Com_T::get(Com_T::Setup_T("com/0/2") .baudRate(115200) .parity(Com_T::Parity_E::NONE_e) ); queue que; Rasl::Os::Mutex_T bufMut; Rasl::Os::Counter_T readDone; struct Reader_T { string rs; bool operator() (char* buf, size_t size, Error_T) { rs += string{buf, buf + size}; auto done = rs.size() >= 7; if(done) { { Rasl::Os::Mutex_T::Guard_T guard(bufMut); que.emplace(move(rs)); } readDone.count(); } return true; } }; } int kiyunMain() { KYLOG_GLOBAL().severity(Logging_T::Severity_E::INFO_e); KYLOG_SCOPE("main"); Reader_T reader0, reader1, reader2; com00.intRead(reader0); com01.intRead(reader1); com02.intRead(reader2); // 10秒钟没有输入则退出 while(readDone.waitFor(10_s)) { string rs = que.front(); que.pop(); KYLOG(INFO) << rs; } return 0; } |
|---|
1) count方法
函数原型:void count();
函数功能:使资源计数加1。应当由“生产者”调用,表示可供“消费者”使用的资源多了一个。
参数:无
返回值:无
2) countAll方法
函数原型:void countAll();
函数功能:应当由“生产者”调用。满足当前所有等待资源的“消费者”。
参数:无
返回值:无
3) wait方法
函数原型:void wait();
函数功能:使资源计数减1。应当由“消费者”调用,如果当前资源计数为0,则当前任务立即阻塞,直到有“生产者”将资源计数增加为止。
参数:无
返回值:无
4) waitFor方法
函数原型:bool waitFor ( Mince :: LowerComputer :: Rasl :: Frame :: Timeout_T );
函数功能:使资源计数减1或者超时。应当由“消费者”调用,如果当前可用资源计数为0,则当前任务立即阻塞,直到有“生产者”增加资源计数或超时为止。
参数:超时时限。
返回值:true:资源计数减1;false:超时。