如何解决如何使用 Keil 的 CMSIS RTOS2 线程和计时器 C 函数创建 C++ 任务类工作线程?
如何将 C++ 类概念映射到 C 函数 osTimerNew() 和 osThreadNew() ?
如何使用 C++ 成员函数作为 Keil RTOS2 osTimerNew() 和 osThreadNew() 回调实现。
谢谢
解决方法
从面向对象的角度来看,我建议您解决这个问题的方法是错误的。线程和计时器之间没有直接关系表明它们应该在单个“类”中,并且这不是机械地将函数“映射”到类的问题。相反,您需要确定类 - 即您想要实例化对象的东西,然后定义接口 - 定义方法这些对象的功能和能力。
为此,我建议线程(或任务)和计时器是单独的类。您可以创建一个周期性任务的更高级别的类,然后可以组合和/或从这些其他类派生。例如:
或
让我们从 cTask
类开始。简单地将 osThreadNew()
函数包装在类包装器中是错误的(或至少毫无意义);相反,您需要将任务视为 class
并考虑该类可能执行的所有操作。为此,CMSIS RTOS 参考为其文档的组织提供了一些灵感。它有一个关于线程管理和线程标志的部分,可用于设计cTask
接口。
一个简单的任务类可能有以下接口示例:
class cTask
{
public:
typedef uint32_t tEventFlags ;
cTask();
virtual ~cTask();
eOSStatus spawn( const char* taskname,int taskpriority = DEFAULT_PRIORITY,int stack_size = DEFAULT_STACK,void* stack_ptr = 0 );
void setEvent( tEventFlags flags ) const ;
static void delay(int period);
static void lock();
static void unlock();
int getPriority() const ;
int setPriority(int new_priority);
private :
virtual void threadMain() = 0 ;
tEventFlags eventWait( tEventFlags flags,int timeout ) ;
static void entry_point( void* arg )
{
cTask* instance = reinterpret_cast<cTask*>(argv) ;
instance->threadMain() ;
}
} ;
然后你可能会有一个任务:
class cMyThread : cTask()
{
public :
cMyThread()
{
spawn( "mythread" ) ;
}
void someEvent()
{
setEvent( 0x0001 ) ;
}
void someOtherEvent()
{
setEvent( 0x0002 ) ;
}
private:
void threadMain()
{
for(;;)
{
tEventFlags event eventWait( 0x0003,WAIT_FOREVER ) ;
if( (event & 0x0001) != 0 )
{
// process some event
}
if( (event & 0x0002) != 0 )
{
// process some other event
}
}
}
} ;
这样你就可以实例化实例 od cMyThread
并与之通信:
cMyThread thread_a ;
cMyThread thread_b ;
thread_a.someEvent() ;
thread_b.someOtherEvent() ;
显然,该接口可以更广泛,您可能希望为信号量、互斥体、消息队列和计时器添加类。
以上仅作说明;如您所见,可能还有很多工作要做,但要回答您的问题 osThreadNew()would be used here to implement
cTask::spawn()and would start the
cTask::threadMain()via the static
entry_point()function by passing it the
this` 指针。
您将采用与 cTimer
类类似的方法,并根据计时器可以执行的操作来定义接口。例如启动、取消、等待、设置事件处理程序等
没有必要盲目地为每个 CMSIS RTOS 功能提供接口; C++ 层提供了一个机会,可以将某些细节抽象为更易于使用且更易于移植到其他 RTOS API 的内容。
,您将“this”提供给 osTimerNew()/osThreadNew() 代替“void * argument”参数。
struct task
{
task ( uint32_t timer_period_ms )
{
// === casting (needs must)
using fp = void ( task::* ) ( void * );
using os_fp = void ( * ) ( void * );
auto cast =
[] ( fp in )
{
union {
fp in;
os_fp out;
} u { in };
return u.out;
};
auto timer_id = osTimerNew
(
cast ( &task::rtos_timer_callback ),osTimerPeriodic,this,// let RTOS know about the object
nullptr
);
m_id_thread = osThreadNew
(
cast ( &task::rtos_thread_callBack ),// let RTOS know about the object
nullptr
);
osTimerStart ( timer_id,timer_period_ms );
}
virtual ~task() = default;
virtual void do_work () = 0;
private:
void rtos_timer_callback ( void * pvArg )
{
osThreadFlagsSet ( m_id_thread,0x01 );
}
__NO_RETURN void rtos_thread_callBack ( void * pvArg )
{
while (1)
{
osThreadFlagsWait ( 0x01,osFlagsWaitAny,osWaitForever );
do_work ();
}
}
private:
osThreadId_t m_id_thread {};
};
现在使用任务类:
struct d_task_0 : public task
{
d_task_0 ( uint32_t timer_period_ms ) : task { timer_period_ms } {}
void do_work () final
{
// called every d_task_0::timer_period_ms
}
};
并创建另一个任务:
struct d_task_1 : public task
{
d_task_1 ( uint32_t timer_period_ms ) : task { timer_period_ms } {}
void do_work () final
{
// called every d_task_1::timer_period_ms
}
};
最后创建工人:
d_task_0 worker0 { 500 }; // d_task_0::do_work () called every 500ms
d_task_1 worker1 { 800 }; // d_task_1::do_work () called every 800ms
RTOS2 文档:
https://www.keil.com/pack/doc/CMSIS/RTOS2/html/group__CMSIS__RTOS__ThreadMgmt.html
https://www.keil.com/pack/doc/CMSIS/RTOS2/html/group__CMSIS__RTOS__TimerMgmt.html
和实施:
https://github.com/ARM-software/CMSIS_5/tree/develop/CMSIS/RTOS2
我的工具链:Keil MDK-ARM Plus 5.33.0.0; ArmClang/Link v6.15
铸造解决方案来自这里:Casting between void * and a pointer to member function
另一种投射方式是:
using os_fp = void ( * ) ( void * );
void ( task::*pTimer ) ( void * ) = &task::rtos_timer_callback;
void * task_timer = ( void*& ) pTimer;
auto timer_id = osTimerNew
(
reinterpret_cast<os_fp>(task_timer),// let RTOS know about the object
nullptr
);
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。