同步机制
aCoral信号量机制不仅可以实现临界资源互斥访问,控制系统中临界资源多个实例的使用,还可以用于维护线程之间、线程和中断之间的同步。
当信号量用来实现同步时,起始值为0,如一个线程正在等待某个I/O操作,当该I/O操作完成后,中断服务程序(或另一个线程)发出信号量,该线程得到信号量后才能继续往下执行。也就是说,某个线程将一直处于等待状态,除非获取了其它线程发给它的信号量。
在实现时,资源的实例数用“1-semNum”来表示,0代表有一个资源,-1代表有两个资源,1代表已经没有资源,且有一个任务在等待该资源。
- 互斥的信号量初始值在创建时设置为1,1-semNum=0,是小于等于0,表明当前没有线程获取该信号量。
- 同步的信号量初始值为0,1-semNum>=0,表明所同步的事件尚未发生。
通信机制
线程之间、线程与中断服务子程序之间还需要通信机制,也就是信息交互。
例如,线程A在执行过程中需要使用线程B(或中断服务子程序)产生的数据,那么B如何将数据传送给A呢?
邮箱
邮箱(MailBox)可以用来实现线程之间同步和通信功能。
假设线程2从邮箱中接收线程1发过来的信息(该信息被称为邮件)。线程2在同步点从邮箱中接收消息,如果线程1此时还没有执行到同步点,则邮箱中是不会有消息的,此时线程2会将自己挂起;当线程1执行到同步点时,会向邮箱中发送一条消息,此时就会激活挂起的线程2,继续执行。
一个线程将需要交互的信息发送到邮箱,另一个线程从邮箱中读出。
邮箱机制依赖于事件控制块acoral_evt_t,acoral_evt_t data成员就是用来挂载线程间传递的信息。
创建一个邮箱
acoral_evt_t *acoral_mbox_create(){
acoral_evt_t *event;
event = acoral_alloc_evt();
if(NULL == event)
return NULL;
event->type = ACORAL_EVENT_MBOX;
event->count = 0x00000000;
event->data = NULL;
acoral_evt_init(event);
return event;
}
发送信息到邮箱
向邮箱中发送信息的接口为acoral_mbox_send(),传入的参数为先前创建的邮箱的地址(类型为邮箱的事件控制块)和指向信息的指针。
acoral_u32 acoral_mbox_send(acoral_evt_t *event,void *msg){
acoral_thread_t *thread;
if(NULL == event){
return MBOX_ERR_NULL;
}
if(event->type != ACORAL_EVENT_MBOX)
return MBOX_ERR_TYPE;
HAL_ENTER_CRITICAL();
if(event->data != NULL){
HAL_EXIT_CRITICAL();
return MBOX_ERR_MES_EXIST;
}
event->data = msg;
thread = acoral_evt_high_thread(event);
// 没有等待队列
if(NULL == thread){
HAL_EXIT_CRITICAL();
return MBOX_SUCCED;
}
timeout_queue_del(thread);
acoral_evt_queue_del(thread);
acoral_rdy_thread(thread);
HAL_EXIT_CRITICAL();
acoral_sched();
return MBOX_SUCCED;
}
从邮箱获取信息
邮箱中没有信息时,将自己挂到邮箱的等待队列;如果邮箱中有消息,则取出消息。
HAL_ENTER_CRITICAL();
if(event->data == NULL){
cur = acoral_running_thread;
acoral_evt_queue_add(event,cur);
acoral_unrdy_thread(cur);
HAL_EXIT_CRITICAL();
acoral_sched();
}
消息
消息机制和邮箱机制很类似,但邮箱一般只能容纳一条信息,消息则会包含一系列消息。
系统定义了一个全局变量g_msgctr_header,通过它可以查找到任一已创建的消息容器。每一个消息容器都可以根据其参数性质来实现不同的通信方式。(如1VS1,1VSn,nVSn,nVS1等)。这里的消息容器只是一个线程间的通信结构acoral_msgctr_t,是消息的存储容器,一个消息容器可以通过它的消息链指针成员,挂载多条消息。而消息结构acoral_msg_t是消息的容器,一个消息结构包含一条消息。
/*消息容器*/
typedef struct{
acoral_res_t res;
acoral_8 *name;
acoral_u8 type;
acoral_list_t msgctr_list; //全局消息列表
acoral_u32 count; //消息容器上已挂消息的数量
acoral_u32 wait_thread_num; //消息容器上已挂等待线程的数量
acoral_list_t waiting; //等待线程链指针
acoral_list_t msglist; //消息链指针
}acoral_msgctr_t;
/*消息*/
typedef struct{
acoral_res_t res;
acoral_list_t msglist; //消息链指针,用于挂载到消息容器
acoral_u32 id; //消息标识
acoral_u32 n;//消息被接受次数,每被接受一次减一,直到0为止
acoral_u32 tt; //消息最大声明周期,ticks计数
void *data; //消息指针
}acoral_msg_t;
创建消息容器
acoral_msgctr_t* acoral_msgctr_create(acoral_u32 *err){
acoral_msg_ctr_t *msgctr;
msgctr = acoral_malloc_msgctr();
if(msgctr == NULL){
return NULL;
}
msgctr->name = NULL;
msgctr->type = ACORAL_MSGCTR;
msg->count = 0;
msgctr->wait_thread_num = 0;
acoral_init_list(&msgctr->msgctr_list);
acoral_init_list(&msgctr->msglist);
acoral_init_list(&msgctr->waiting);
acoral_list_add2_tail(&msgctr->msgctr_list,&(g_msgctr_header.head)); // 将初始化后的消息容器挂到全局消息容器队列g_msgctr_header上。
}
msgctr = acoral_alloc_msgctr(); 申请一片内存空间,从内存资源池中获取一个资源对象供消息容器结构acoral_msgctr_t使用。
acoral_msgctr_t *acoral_alloc_msgctr()
{
return (acoral_msgctr_t *)acoral_get_res(&acoral_msgctr_pool_ctr);
}
extern acoral_queue_t g_msgctr_header;
在g_msgctr_header在message.h中定义,extern acoral_queue_t g_msgctr_header;这样就可以在任何需要的地方找到这个消息容器。
创建消息
消息容器并不直接包含消息,在消息容器之下,还有一层是消息结构,因而消息的创建,先是创建消息结构,再将消息挂到消息结构。
acoral_msg_t* acoral_msg_create(acoral_u32 n,acoral_u32 *err,acoral_u32 id,acoral_u32 nTtl, codi *data){
acoral_msg_t *msg;
msg = acoral_alloc_msg();
if(msg == NULL)
return NULL;
msg->id = id;
msg->n = n;
msg->ttl = nTtl;
msg->data = data;
acoral_init_list(&msg-msglist);// 将初始化后的消息挂到消息队列上
return msg;
}
发送消息
消息发送时,首先将包含消息的消息结构挂到消息容器的消息链上,然后判断是否有等待的线程,如果有的话,则唤醒最高优先级的线程。
acoral_u32 acoral_msg_send(acoral_msgctrl_t* msgctr,acoral_msg_t *msg){
acoral_enter_critical();
if(NULL == msgctr){
acoral_exit_critical();
return MSG_ERR_NULL;
}
if(NULL == msg){
acoral_exit_critical();
return MSG_ERR_NULL;
}
/*消息数限制*/
if(ACORAL_MESSAGE_MAX_COUNT <= msgctr->count){
acoral_exit_critical();
return MSG_ERR_COUNT;
}
/*增加消息,将包含消息的消息结构挂到消息容器的消息链上*/
msgctr->count++;
msg->ttl += acoral_get_ticks(&msg->msglist,&msgctr->msglist);
/*唤醒等待*/
if(msgctr->wait_thread_num > 0){
/*唤醒最高优先级线程*/
wake_up_thread(&msgctr->waiting);
msgctr->wait_thread_num--;
}
acoral_exit_critical();
acoral_sched();
return MSGCTR_SUCCED;
}
消息接收
消息接收函数的接口为void *acoral_msg_recv(acoral_msgctr_t *msgctr, acoral_u32 id,acoral_time timeout,acoral_u32 *err),需要的参数是消息容器指针msgctr,指出要从哪个消息容器接收消息,指定接收消息的ID,超时时间和错误返回码。
void *acoral_msg_recv(acoral_msgctr_t *msgctr, acoral_u32 id,acoral_time timeout,acoral_u32 *err){
void *data;
acoral_list_t *p,*q;
acoral_msg_t *pmsg;
acoral_thread_t *cur;
if(acoral_intr_nesting > 0){
*err = MSG_ERR_INTR;
return NULL;
}
if(NULL == msgctr){
*err = MSG_ERR_NULL;
return NULL;
}
cur = acoral_cur_thread;
acoral_enter_critical();
if(timeout > 0){ //需要进行超时处理,以ms为单位
cur->delay = TIME_TO_TICKS(timeout);
timeout_queue_add(cur);
}
while(1){
p = &msgctr->msglist;
q = p->next;
for(;p!=q;q=q->next){
pmsg = list_entry(q,acoral_msg_t,msglist);
if((pmsg->id==id)&&(pmsg->n>0)){
pmsg->n--;
timeout_queue_del(cur);
data = pmsg->data;
acoral_list_del(q);
acoral_release_res((acoral_res_t *)pmsg);
msgctr->count--;
acoral_exit_critical();
return data;
}
}
/*没有接收消息*/
msgctr->wait_thread_num++;
acoral_msgctr_queue_add(msgctr,cur);
acoral_unrdy_thread(cur);
acoral_exit_critical();
acoral_sched();
/*看是否超时*/
if(timeout > 0 && (acoral_32)cur->delay <= 0)
break;
}
/*超时退出*/
if(msgctr->wait_thread_num > 0)
msgctr->wait_thread_num--;
acoral_list_del(&cur->waiting);
acoral_exit_critical();
*err = MSG_ERR_TIMEOUT;
return NULL;
}
删除消息容器
/*pmsgctr消息容器指针,flag为参数指针,用于区分是否强制删除消息容器,如果指定强制删除,则会先将消息结构释放,然后将等待线程全部就绪,最后释放该消息容器结构。如果不指定强制删除,只有在容器上没有挂载消息和无等待线程时才会将其释放,否则返回错误。*/
acoral_u32 acoral_msg_del(acoral_msgctr_t *pmsgctr,acoral_u32 flag){
acoral_list_t *p,*q;
acoral_thread_t *thread;
acoral_msg_t *pmsg;
if(NULL == pmsgctr)
return MST_ERR_NULL;
//非强制删除
if(flag == MST_DEL_UNFORCE){
if((pmsgctr->count>0) || (pmsgctr->wait_thread_num > 0))
return MST_ERR_UNDEF;
else{
acoral_release_res((acoral_res_t *)pmsgctr);
}
}else{
//强制删除
if(pmsgctr->wait_thread_num > 0){
p = &msgctr->waiting;
q = p->next;
for(;q!=p;q=q->next){
thread=list_entry(q,acoral_thread_t,waiting);
acoral_rdy_thread(thread);
}
}
//释放消息结构
if(msgctr->count>0){
p = &msgctr->msglist;
q = p->next;
for(;p!=q;q=q->next){
pmsg = list_entry(q,acoral_msg_t,msglist);
acoral_list_del(q);
acoral_release_res((acoral_res_t *)pmsg); }
}
acoral_release_res((acoral_res_t *)pmsgctr);
}
}
/*删除消息*/
acoral_u32 acoral_msg_del(acoral_msg_t *msg){
if(NULL != pmsg){
acoral_release_res((acoral_res_t *)pmsg);
}
}