Race condition
Race Condition은 멀티스레드 또는 멀티태스킹 환경에서 여러 스레드 또는 태스크가 공유된 자원에 동시에 접근하려고 할 때 발생하는 문제를 나타냅니다. OSEK RTOS 환경에서도 race condition이 발생할 수 있습니다.
Race Condition이 발생하는 상황은 주로 다음과 같습니다:
- 공유 자원에 동시 접근: 여러 태스크가 동시에 공유 변수, 자료구조, 메모리 영역 등에 접근할 때 발생합니다.
- 스케줄링의 불확실성: 다양한 태스크들이 스케줄링에 의해 실행되는 순서가 예측하기 어려울 때 발생합니다.
- 비원자적 연산 수행: 여러 단계로 이뤄진 연산 중 일부 단계만 수행되고 다른 태스크가 끼어들어 해당 연산을 완전히 수행하기 전에 결과를 읽는 경우 등이 해당됩니다.
Race Condition이 발생하면 예기치 않은 결과, 데이터 손상, 시스템의 불안정성 등의 문제가 발생할 수 있습니다. 이를 방지하기 위해 OSEK에서는 다양한 동기화 메커니즘을 제공합니다. 예를 들면, 뮤텍스(Mutex), 세마포어(Semaphore), 이벤트(Event) 등을 사용하여 공유 자원에 대한 접근을 조절하고 동기화를 유지할 수 있습니다.
실습을 통해 Race condition에 대해 이해하는 시간을 가지겠습니다.
Race condition 실습
실습을 위한 Task와 자원 접근 조건에 대해 말씀드리겠습니다.
- Task1 = Low priority, AUTOSTART
- Task2 = High priority, periodic, activation (1ms period)
- 공유 자원 접근은 volatile unsigned long shared라는 전역변수를 통해 하겠습니다.
- Task1 은 shared++를 100만번합니다.
- Task2는 주기적으로 실행하며 shared++를 합니다.
- Timer 주기를 1 msec로 설정합니다.
코드를 작성해보겠습니다.
bsw.c 파일을 수정하여 Timer주기를 변경하겠습니다.
#define TIMER_US 1000U /* 1 msec */
조건에 맞춰 asw.c 파일을 작성합니다.
#include "bsw.h"
volatile unsigned long shared = 0;
ISR2(TimerISR)
{
IncrementCounter(counter1);
}
TASK(Task1){
unsigned long i;
printfSerial("Task1 Begins...\n");
for(i = 0; i<1000000; i++){
shared++;
}
printfSerial("Added 1000000 to shared\n");
printfSerial("shared = %4lu\n", shared);
printfSerial("Task1 finishes...");
TerminateTask();
}
TASK(Task2){
static unsigned long i=0;
if(i<1000)
{
shared++;
}
else if(i==1000)
{
printfSerial("Added 1000 to shared\n");
}
i++;
TerminateTask();
}
조건에 맞춰 OIL파일을 작성합니다.
CPU mySystem {
OS myOs {
EE_OPT = "OS_EE_APPL_BUILD_DEBUG";
EE_OPT = "OS_EE_BUILD_DEBUG";
USERESSCHEDULER = TRUE;
CPU_DATA = AVR8 {
MULTI_STACK = TRUE;
};
MCU_DATA = MEGA {
MODEL = MEGA_328p;
};
LIB = ARDUINO {
SDK_BOARD = UNO;
VARIANT = CC {
VERSION = "1.8.5";
};
STAND_ALONE = TRUE; // Generate Arduino libraries
};
KERNEL_TYPE = OSEK {
CLASS = ECC2; // Default
};
};
APPDATA myApp {
APP_SRC = "bsw.cpp";
APP_SRC = "asw.c";
};
COUNTER counter1{
MINCYCLE = 1;
MAXALLOWEDVALUE = 127;
TICKSPERBASE = 1;
};
ALARM alarm1{
COUNTER = counter1;
ACTION = ACTIVATETASK{
TASK = Task2;
};
AUTOSTART = TRUE{
ALARMTIME = 0;
CYCLETIME = 1;
};
};
TASK Task1{
PRIORITY = 1;
STACK = SHARED;
SCHEDULE = FULL;
AUTOSTART = TRUE;
ACTIVATION = 1;
};
TASK Task2{
PRIORITY = 2;
STACK = SHARED;
SCHEDULE = FULL;
AUTOSTART = FALSE;
ACTIVATION = 1;
};
ISR TimerISR{
CATEGORY = 2;
SOURCE = "TIMER1_COMPA";
};
};
실행결과

위의 결과를 보면 shared의 값이 100536로 증가된 것을 확인 할 수 있습니다.
우리가 원하던 조건은 Task1 은 shared++를 100만번하고, Task2는 주기적으로 실행하며 shared++를 하는것 이였습니다.
이때 Task2는 1000만 돌아가도록 코드를 작성했었기에 shared의 값은 1001000이 되었어야 합니다.
Task가 공유된 자원에 동시에 접근하려고 할 때 발생하는 문제를 나타냅니다각했던 위의 상황이 Race condition상황이라 볼 수 있습니다.
OSEK resource
OSEK RTOS에서 “resource(리소스)“는 공유 자원에 대한 접근을 동기화하고, 경쟁 조건(Race Condition)을 방지하기 위한 동기화 메커니즘 중 하나입니다. 리소스는 주로 공유된 변수, 데이터 구조, 장치 또는 코드 영역과 같은 공유 자원을 나타냅니다.
리소스는 크게 두 가지 타입으로 나눌 수 있습니다
- Internal Resource(내부 리소스): 태스크 내에서만 접근 가능한 리소스로, 해당 태스크의 코드 영역에 대한 접근을 제한합니다.
- External Resource(외부 리소스): 여러 태스크 간에 공유되는 리소스로, 여러 태스크가 동시에 접근할 수 있습니다.
리소스를 사용하여 공유 자원에 대한 접근을 동기화할 때는 다음과 같은 OSEK API 함수들이 사용됩니다
- GetResource(resourceName): 리소스를 획득(락)합니다. 이미 다른 태스크에 의해 획득된 리소스에 대해선 해당 태스크는 대기 상태로 전이됩니다.
- ReleaseResource(resourceName): 획득한 리소스를 반납(언락)합니다.
Race condition을 OSEK의 Resource를 사용하여 해결해보는 실습을 진행해보겠습니다.
OSEK resource 실습
OIL 파일을 수정하여 resource를 사용할 수 있도록 수정하고 Task1에 resource를 추가해주겠습니다.
RESOURCE S1{
RESOURCEPROPERTY = STANDARD;
};
TASK Task1{
PRIORITY = 1;
STACK = SHARED;
SCHEDULE = FULL;
AUTOSTART = TRUE;
ACTIVATION = 1;
RESOURCE = S1;
};
asw.c 파일에서 Task1과 Task2의 shared를 증가 시키는 부분 앞뒤로 resource를 사용 할 수 있도록 수정합니다.
TASK(Task1){
unsigned long i;
printfSerial("Task1 Begins...\n");
for(i = 0; i<1000000; i++){
GetResource(S1);
shared++;
ReleaseResource(S1);
}
printfSerial("Added 1000000 to shared\n");
printfSerial("shared = %4lu\n", shared);
printfSerial("Task1 finishes...");
TerminateTask();
}
TASK(Task2){
static unsigned long i=0;
if(i<1000)
{
GetResource(S1);
shared++;
ReleaseResource(S1);
}
else if(i==1000)
{
printfSerial("Added 1000 to shared\n");
}
i++;
TerminateTask();
}
실행결과

'Embedded > OSEK Real-Time OS' 카테고리의 다른 글
Mutex (0) | 2024.01.21 |
---|---|
Hook (0) | 2024.01.21 |
Alarm & Event (0) | 2024.01.20 |
Task (0) | 2024.01.20 |
OSEK project 기초 (0) | 2024.01.20 |