首页 > 其他分享 >计数信号量的原理与创建

计数信号量的原理与创建

时间:2024-12-14 19:29:23浏览次数:6  
标签:tTask 创建 void 信号量 计数 tEvent include uint32

目录

计数信号量

设计原理

设计实现


计数信号量

信号量就是一个带事件控制的计数器,在其上定义了三个操作:

  • 可以被初始化一个非负数
  • wait操作:若该值为0,则执行操作的任务等待;否则将计数值减1
  • notify操作:将信号量的值增1后,若该值为非正,则执行操作的任务唤醒

设计原理

  • 计数器负责计数控制
  • 事件控制块用于控制任务等待与唤醒

设计实现

  • 定义信号量(事件控制块、计数器、最大计数值)
  • 初始化信号量

tSem.c

#include "tSem.h"

/* 信号量初始化函数 */
void tSemInit(tSem *sem, uint32_t startCount, uint32_t maxCount)
{
	tEventInit(&sem->event, tEventTypeSem);//事件控制块初始化
	
	sem->maxCount = maxCount;
	if(maxCount == 0)//计数值没有限制
	{
		sem->count = startCount;
	}
	else
	{
		sem->count = (startCount > maxCount) ? maxCount : startCount;//检查参数有没有传递正确
	}
}

tSem.h

#ifndef __TSEM_H
#define __TSEM_H

#include "tEvent.h"

typedef struct _tSem
{
	tEvent event;				//事件控制块
	uint32_t count;			//计数器
	uint32_t maxCount;	//最大计数值
}tSem;

void tSemInit(tSem *sem, uint32_t startCount, uint32_t maxCount);

#endif

tEvent.h

#ifndef __TEVENT_H
#define __TEVENT_H

#include "tTask.h"

/* 事件控制块类型 */
typedef enum _tEventType{
	tEventTypeUnknow,
	tEventTypeSem, 		//计数信号量
}tEventType;

/* 事件控制块 */
typedef struct _tEvent{
	tEventType type;		//事件控制块类型
	tList waitList;			//等待列表
}tEvent;


void tEventInit(tEvent *event, tEventType type);
void tEventWait(tEvent *event, tTask *task, void *msg, uint32_t state, uint32_t timeout);
tTask *tEventWakeUp(tEvent *event, void *msg, uint32_t result);
void tEventRemoveTask(tTask *task, void *msg, uint32_t result);
uint32_t tEventRemoveAll(tEvent *event, void *msg, uint32_t result);
uint32_t tEventWaitCount(tEvent *event);

#endif

tinyOS.h

#ifndef __TINYOS_H
#define __TINYOS_H

#include <stdint.h>
#include "tLib.h"
#include "tConfig.h"
#include "tTask.h"
#include "tEvent.h"
#include "tSem.h"

/* 错误码 */
typedef enum _tError{
	tErrorNoError = 0,		//没有错误发生
	tErrorTimeout = 1,		//超时
}tError;

extern tTask *currentTask;			
extern tTask *nextTask;				

uint32_t tTaskEnterCritical(void);
void tTaskExitCritical(uint32_t status);

void tTaskSwitch(void);		//和CPU相关,写在switch.c
void tTaskRunFirst(void);

void tTaskSchedInit(void);
void tTaskSchedDisable(void);
void tTaskSchedEnable(void);
void tTaskSchedRdy(tTask *task);
void tTaskSchedUnRdy(tTask *task);
void tTaskSchedRemove(tTask *task);
void tTaskSched(void);
void tTimeTaskWait(tTask *task, uint32_t ticks);
void tTimeTaskWakeUp(tTask *task);
void tTimeTaskRemove(tTask *task);
void tTaskSystemTickHandler(void);
void tTaskDelay(uint32_t delay);


void tSetSysTickPeriod(uint32_t ms);
void tInitApp(void);

	
#endif

app.c

#include "tinyOS.h"

//定义任务,分别为它们配备独立的堆栈空间
tTask tTask1;
tTask tTask2;
tTask tTask3;
tTask tTask4;
tTaskStack task1Env[1024];
tTaskStack task2Env[1024];
tTaskStack task3Env[1024];
tTaskStack task4Env[1024];

tSem sem;

//定义任务要执行的功能
int task1Flag;
void task1Entry(void *param)
{
	tSetSysTickPeriod(10);//初始化
	
	tSemInit(&sem, 1, 10);
	
	for(;;)//任务里是for的死循环
	{
		task1Flag = 0;
		tTaskDelay(1);
		task1Flag = 1;
		tTaskDelay(1);
	}
}

int task2Flag;
void task2Entry(void *param)
{
	for(;;)
	{
		task2Flag = 0;
		tTaskDelay(1);
		task2Flag = 1;
		tTaskDelay(1);
	}
}
int task3Flag;
void task3Entry(void *param)
{
	for(;;)
	{
		task3Flag = 0;
		tTaskDelay(1);
		task3Flag = 1;
		tTaskDelay(1);
	}
}
int task4Flag;
void task4Entry(void *param)
{
	for(;;)
	{
		task4Flag = 0;
		tTaskDelay(1);
		task4Flag = 1;
		tTaskDelay(1);
	}
}

/* 应用任务初始化函数 */
void tInitApp(void)
{
	//最后一个参数:传堆栈末端地址,因为堆栈是向下生长的,初始堆栈地址是堆栈空间最后一个单元地址的末端
	tTaskInit(&tTask1, task1Entry, (void *)0x11111111, 0, &task1Env[1024]);
	tTaskInit(&tTask2, task2Entry, (void *)0x22222222, 1, &task2Env[1024]);
	tTaskInit(&tTask3, task3Entry, (void *)0x22222222, 1, &task3Env[1024]);
	tTaskInit(&tTask4, task4Entry, (void *)0x22222222, 1, &task4Env[1024]);
}

标签:tTask,创建,void,信号量,计数,tEvent,include,uint32
From: https://blog.csdn.net/daybydayby/article/details/144472847

相关文章

  • 时间控制块的原理与创建
    目录问题概述事件控制块原理设计实现问题概述如何同步两个任务的运行?如何处理多个任务共享资源的冲突问题?如何在多个任务间传递消息通信?如何在中断ISR与任务之间传递多个事件标志?事件控制块原理任务在事件控制块上等待,暂停运行事件发生,通知事件控制块事件控制块通......
  • Java中创建线程的几种方式
    盘点一下Java中创建线程的几种方式一、继承Thread类,重写run()方法publicclassMyThreadextendsThread{@Overridepublicvoidrun(){System.out.println("mythreadstart"+Thread.currentThread().getName());}publicstaticvoidmain......
  • 如何创建和使用Python虚拟环境
    在Python开发中,使用虚拟环境是一个非常重要的实践。它可以帮助我们隔离项目依赖,避免不同项目之间的包冲突。本文将详细介绍如何创建、激活、使用和退出虚拟环境。1.创建虚拟环境首先,我们需要使用venv模块来创建一个虚拟环境。以下命令将在当前目录下创建一个名为venv的虚拟环境......
  • 【Linux】:多线程(POSIX 信号量 、基于环形队列的生产消费者模型)
    ......
  • 函数栈帧的创建和销毁(逐步分析)
    1.栈1.1什么是栈什么是栈?在内存中栈是一种特殊的数据结构,它遵循后进先出的规则。内存中的栈通常用于存储临时变量,函数调用的上下文(每一次函数调用,都会在内存上创建空间,用来存放函数参数,函数返回值,临时变量等),返回的地址,栈是由操作系统管理的。1.2栈在内存中的表示在内存......
  • 如何在易优EyouCMS中手动创建缺失的数据表?
    在使用易优EyouCMS时,如果遇到数据表缺失的情况,您可以通过以下步骤手动创建缺失的数据表:确认数据表缺失:登录到您的数据库管理工具(如phpMyAdmin),检查报错中提到的数据表是否存在于当前数据库中。例如,如果报错提示“数据表 ey_product_spec_value_handle 不存在”,请在数据库中......
  • 【设计模式与体系结构】创建型模式-单例模式
    引言张三和其舍友收假后回到宿舍,并闲聊了起来。张三说:“我昨天吃了家店,菜品很不错。”其舍友也说:“我昨天也在校门口一家新开的店吃了一下,那家新开的店也很不错。”张三说:“我昨天吃的是鸡公煲,你吃的是什么?”其舍友说:“巧了,我吃的也是鸡公煲。”张三说:“学校门口有好几家鸡公煲呢......
  • 手动创建swap扩大内存
    1.创建swap文件夹#在根目录创建/swap文件夹并切换目录到/swapmkdir/swap&&cd/swap2.创建要作为swap分区的文件:增加1GB大小的交换分区,则命令写法如下,其中的count等于想要的块的数量(bs*count=文件大小)。一般swap的大小为物理内存的1.5-2倍。内存<=4g:Swap至少4G......
  • guassdb华为OpenGauss高斯数据库间隔分区表自动创建分区sql实例
    命令行操作流程#切换用户su-omm#连接数据库gsql-dpostgres-p6432-r#选择数据库\cenv_demo#设置查询模式SETSEARCH_PATHTOpublic;sql模板1、预创建时间范围sql分区(非数据库自动创建分区)CREATETABLEt_metadata(idVARCHAR(36)NOTNULLPRIMA......
  • AD学习笔记·创建原理图封装,调用别人原理图封装
                    编写不易,请勿搬运,仅供学习,感谢理解。        前言:本文参考,B站忆凡教育的课程,连接放在最后。原理图封装要求    在进行原理图绘制的时候,需要调用元器件的原理图库,在嘉立创eda里面,一般使用快捷键shift+f就能......