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

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

同步机制

aCoral信号量机制不仅可以实现临界资源互斥访问控制系统中临界资源多个实例的使用还可以用于维护线程之间、线程和中断之间的同步。

当信号量用来实现同步时起始值为0如一个线程正在等待某个I/O操作当该I/O操作完成后中断服务程序或另一个线程发出信号量该线程得到信号量后才能继续往下执行。也就是说某个线程将一直处于等待状态除非获取了其它线程发给它的信号量。
在实现时资源的实例数用“1-semNum”来表示0代表有一个资源-1代表有两个资源1代表已经没有资源且有一个任务在等待该资源。

  • 互斥的信号量初始值在创建时设置为11-semNum=0是小于等于0表明当前没有线程获取该信号量。
  • 同步的信号量初始值为0,1-semNum>=0表明所同步的事件尚未发生。

通信机制

线程之间、线程与中断服务子程序之间还需要通信机制也就是信息交互。
例如线程A在执行过程中需要使用线程B或中断服务子程序产生的数据那么B如何将数据传送给A呢

邮箱

邮箱MailBox可以用来实现线程之间同步和通信功能。
在这里插入图片描述
假设线程2从邮箱中接收线程1发过来的信息该信息被称为邮件。线程2在同步点从邮箱中接收消息如果线程1此时还没有执行到同步点则邮箱中是不会有消息的此时线程2会将自己挂起当线程1执行到同步点时会向邮箱中发送一条消息此时就会激活挂起的线程2继续执行。
一个线程将需要交互的信息发送到邮箱另一个线程从邮箱中读出。
邮箱机制依赖于事件控制块acoral_evt_tacoral_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通过它可以查找到任一已创建的消息容器。每一个消息容器都可以根据其参数性质来实现不同的通信方式。如1VS11VSnnVSnnVS1等。这里的消息容器只是一个线程间的通信结构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);
	}
}
阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6