嵌入式实时操作系统的设计与开发(九)

同步机制

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);
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

饼干饼干圆又圆

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值