본문 바로가기
Embedded/OSEK Real-Time OS

Task

by kjy1010 2024. 1. 20.

OSEK RTOS에서의 Task에 대해 알아보겠습니다.

Task
Task는 실행되어야 하는 코드 블록을 나타내며, 시스템의 주요 기능을 수행하는 데 사용됩니다. 각 태스크는 우선순위를 가지며, 시스템은 우선순위에 따라 태스크를 스케줄링하여 실행합니다.

  • 작업 수행: 태스크의 주요 역할은 특정 작업 또는 일련의 작업을 수행하는 것입니다. 작업은 시스템의 요구사항에 따라 다양하게 정의될 수 있으며, 예를 들어 센서 읽기, 데이터 처리, 통신 등이 해당될 수 있습니다.
  • 우선순위 지정: 각 태스크는 특정 우선순위를 가지며, 시스템은 이 우선순위에 따라 태스크를 스케줄링합니다. 높은 우선순위를 가진 태스크는 낮은 우선순위를 가진 태스크보다 더 높은 우선순위로 실행됩니다.
  • 스케줄링 및 동기화: OSEK RTOS는 멀티태스킹 환경에서 여러 태스크가 동시에 실행되는 것을 지원합니다. 각 태스크는 정확한 타이밍에 실행될 수 있도록 스케줄링됩니다. 또한 OSEK는 동기화 메커니즘을 제공하여 공유 자원에 대한 접근을 조절하고 크리티컬 섹션을 관리할 수 있습니다.
  • 태스크 상태 관리: OSEK RTOS에서는 태스크가 실행 중, 대기 중, 중지된 상태 등 여러 상태로 전이될 수 있습니다. 이 상태 변화는 시스템의 효율적인 운영을 지원하고, 작업이 이벤트에 의해 활성화되거나 대기 상태로 들어갈 수 있도록 합니다.
  • 알람 및 이벤트 활용: OSEK 태스크는 알람과 이벤트를 통해 실행을 트리거할 수 있습니다. 특정 조건이 충족되면 알람이나 이벤트에 의해 활성화되어 해당 태스크가 실행됩니다.


코드를 작성해보며 Task에 대해 이해해보는 시간을 가지겠습니다.
이전 포스팅의 코드에서 Priority 2를 가지는 Task2를 추가해줍니다. 이때 Priority는 우선 순위를 설정하기 위한 변수이면 높은 숫자가 높은 우선 순위를 가집니다.
asw.c 파일 수정

TASK(Task1)
{
	printfSerial(“Task1 Begins…”);
	mdelay(3000);
	printfSerial(“Task1 Finishes…”);

	TerminateTask();
}

TASK(Task2)
{
	printfSerial(“Task2 Begins…”);
	mdelay(3000);
	printfSerial(“Task2 Finishes…”);

	TerminateTask();
}


OIL파일 수정

TASK Task2{
	PRIORITY = 2;
	STACK = SHARED;
	SCHEDULE = FULL;
	AUROSTART = TRUE;
	ACTIVATION = 1;
};


실행결과


코드를 실행시키면 위의 화면과 같이 Task2가 먼저 시작하고, Task2가 종료후 Task1이 시작됩니다.

Task Activation

Task Activation(태스크 활성화)은 OSEK RTOS에서 특정 태스크를 실행 가능한 상태로 전환하는 과정을 나타냅니다. 이는 주로 이벤트나 알람과 연결되어 있어 특정 조건이 충족될 때 태스크가 실행될 수 있도록 하는 중요한 메커니즘 중 하나입니다.

기본적으로 태스크는 활성화되기 전에는 실행되지 않습니다. Task Activation은 다양한 상황에서 발생할 수 있으며, 그 중에서 주요한 두 가지 경우는 다음과 같습니다

  • 이벤트 기반 활성화: 태스크는 특정 이벤트가 발생했을 때 활성화될 수 있습니다. 이벤트는 소프트웨어나 하드웨어에서 발생할 수 있으며, 이벤트에 대한 감지 및 처리로 태스크가 활성화됩니다.
  • 알람 기반 활성화: 알람은 시간 기반으로 동작하며, 특정 시간에 태스크를 활성화합니다. 이는 주로 주기적인 작업을 수행하기 위해 활용됩니다.


Task Activation는 실시간 시스템에서 작업을 트리거하고 스케줄링하는 핵심 메커니즘 중 하나로, 정확한 타이밍과 이벤트에 의한 활성화를 통해 신뢰성 높은 시스템 운영을 지원합니다.

실습을 통해 이해해보는 시간을 가지겠습니다.
Timer가 Task1을 activate하고 Task1이 Task2를 activate하도록 코드를 수정해보겠습니다.

asw.c파일 수정

ISR2(TimerISR)
{
   static long c = -4;
	if(c == 0)
		ActivateTask(Task1);
   printfSerial("\n%4ld: ",c++);
}
TASK(Task1){
   printfSerial("Task1 Begins...");
   mdelay(3000);
   printfSerial("Task1 Finishes...");
   TerminateTask();
}

TASK(Task2){
   printfSerial("Task2 Begins...");
   mdelay(3000);
   printfSerial("Task2 Finishes...");
   TerminateTask();
}


OIL파일 수정

TASK Task1{
	PRIORITY = 2;
	STACK = SHARED;
	SCHEDULE = FULL;
	AUROSTART = FALSE;
	ACTIVATION = 1;
};

TASK Task2{
	PRIORITY = 2;
	STACK = SHARED;
	SCHEDULE = FULL;
	AUROSTART = FALSE;
	ACTIVATION = 1;
};


실행결과

위의 화면처럼 타이머가 4초후 Task1를 activate하고 3초의 딜레이를 가진후 Task2를 activate 합니다. 그리고 나서 3초의 딜레이를 가진후 Task1이 종료되면서 Task2가 시작하는 결과를 확인 할 수 있습니다.
그럼 Task2가 우선순위가 높으면 어떠한 결과가 나올까요? 각자 코드를 수정해보고 결과를 보겠습니다.

실행결과

이전 case와 같이 Timer가 4초 후 Task1를 activate하는 것은 변함이 없습니다. 하지만 Task1이 3초의 딜레이를 가진 후 우선순위가 높은 Task2가 시작되는 모습을 확인 할 수  있으며, Task2가 종료 된 후 Task1이 나머지 동작을 수행하는 것을 확인 할 수 있습니다.
따라서 Task를 사용할때는 우선순위를 고려하여 사용하는 것이 중요합니다.

GetTaskID
Task의 ID를 확인 하는 방법입니다.
asw.c를 수정해보겠습니다.

TASK(Task1)
{
	TaskType id;
	printfSerial(“Task1 Begins…”);
	mdelay(3000);
	ActivateTask(Task2);
	mdelay(3000);
	GetTaskID(&id);
	printfSerial(“Task ID = %d…”,id);
	printfSerial(“Task1 Finishes…”);
	TerminateTask();
}

TASK(Task2)
{
	TaskType id;
	printfSerial(“Task2 Begins…”);
	mdelay(3000);
	GetTaskID(&id);
	printfSerial(“Task ID = %d…”,id);
	printfSerial(“Task2 Finishes…”);
	TerminateTask();
}


실행결과


다음과 같이 Task ID를 출력하는 것을 확인 할 수 있습니다.

GetTaskState
Task의 State를 확인 하는 방법을 알아보겠습니다.
하나의 Task를 추가하여 이를 Task1과 Task2의 state를 알아내는데 사용해보도록 하겠습니다.

asw.c을 수정하여 TaskM을 추가

TASK(TaskM)
{
	printState(Task1);
	printState(Task2);

	TerminateTask();
}

OIL파일에도 TaskM을 추가

TASK TaskM{
    	PRIORITY = 3;
       STACK = SHARED;
       SCHEDULE = FULL;
       AUTOSTART = FALSE;
       ACTIVATION = 1;
    };


asw.c파일에 state함수를 추가

void printState(TaskType id){
	TaskStateType state;

	if(GetTaskState(id,&state)==E_OK){
		switch (state){
		case SUSPENDED:
			printfSerial("%d: suspended...",id);
			break;
		case READY:
			printfSerial("%d: ready...",id);
			break;
		case WAITING:
			printfSerial("%d: waiting...",id);
			break;
		case RUNNING:
			printfSerial("%d: running...",id);
			break;
		}
	}


asw.c파일에서 Task1과 Task2수정

TASK(Task1){
	TaskType id;
   printfSerial("Task Begins...\n");
   printState(Task1);
   printState(Task2);
   mdelay(3000);
   ActivateTask(Task2);
   printState(Task1);
      printState(Task2);
   mdelay(3000);
   GetTaskID(&id);
   printfSerial("Task ID = %d...",id);
   printfSerial("Task1 Finishes...\n");
   ChainTask(TaskM);
}

TASK(Task2){
	TaskType id;
	printfSerial("Task2 Begins...\n");
	printState(Task1);
	   printState(Task2);
	mdelay(3000);
	GetTaskID(&id);
	   printfSerial("Task ID = %d...",id);
	printfSerial("Task2 Finishes...\n");
	 ChainTask(TaskM);
}


실행결과


다음과 같이 Task ID와 Task의 상태를 출력하는 것을 확인 할 수 있습니다.


'Embedded > OSEK Real-Time OS' 카테고리의 다른 글

Hook  (0) 2024.01.21
Alarm & Event  (0) 2024.01.20
OSEK project 기초  (0) 2024.01.20
OSEK project 생성과 파일구조  (0) 2024.01.18
OSEK RTOS 실습 환경 구축  (0) 2024.01.17