임계영역 보호


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
#include "includes.h"
 
 
int tickets;        // MAX value( 1000 million )
int backupTickets;
int T1_Ticket=0, T2_Ticket= 0;
 
/* ...........................................................................
 *
 * 태스크 스택 정의
 * ===================
 */
OS_STK TaskStartStk[TASK_STK_SIZE]; /* START task stack */
OS_STK Task1Stk[TASK_STK_SIZE]; /* Task #1 stack */
OS_STK Task2Stk[TASK_STK_SIZE]; /* Task #2 stack */
//OS_STK Task3Stk[TASK_STK_SIZE]; /* Task #3 stack */
//OS_STK Task4Stk[TASK_STK_SIZE]; /* Task #4 stack */
 
/* ...........................................................................
 *
 * 사용자 메모리 정의
 * ===================
 */
TASK_USER_DATA  TaskUserData[7];
 
/* ...........................................................................
 *
 * 이벤트 컨트롤 & 사용자 정의 블럭 정의
 * ===================
 */
#define TICKET_1BILLION        1000000000
#define TICKET_1MILLION        1000000
#define TICKET_10000        10000
#define TICKET_1000            1000
 
extern void seedrand(int seed);
extern int randomnumber(void);
int buyTicket(void);
 
// 1초마다 콘솔에 동작중을 표시(.)
extern INT32U USE_OSTimeTickHook;
 
/* ...........................................................................
 *
 * 태스크 함수 원형
 * ===================
 */
void  TaskStart(void *pdata); /* Function prototypes of Startup task */
void  Task1(void *pdata);
void  Task2(void *pdata);        
void  Task3(void *pdata);
void  Task4(void *pdata);
 
//
// 어플리케이션 메인 루틴
//
int main(void)
{
    OSInit(); /* microC/OS-II 초기화 */
 
    PC_ElapsedInit(); /* Initialized elapsed time measurement     */
 
    strcpy(TaskUserData[TASK_START_ID].TaskName, "TaskStart");
    
    // TASK CREATE
    OSTaskCreateExt(TaskStart,
                   (void *)0,
                   &TaskStartStk[TASK_STK_SIZE-1],
                   TASK_START_PRIO,
                   TASK_START_ID,
                   &TaskStartStk[0],
                   TASK_STK_SIZE,
                   &TaskUserData[TASK_START_ID],
                   OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR);
 
    OSStart(); /* start scheduler */
 
    return 0;    
}
 
//
// 태스크 'START'
//
void  TaskStart (void *pdata)
{
    INT8U err;
    
    pdata = pdata;                /* 컴파일러 경고를 막기 위함 */
 
    // 시스템 초기화(UART, LCD, TimeTick)
    InitSystem();    
 
    OSStatInit();                /* Initialize uC/OS-II's 통계 함수 */
 
    //
    // set random seed
    //
    seedrand( 45 );
    
    //
    // Set Tickets
    //
    /* TODO #2: 
        초기 티켓수를 작은수(10,000 ~ 100,000정도) 입력 하여 테스트 한후 
        그 결과를 설명한다 */
#if 1 // No comment
    //tickets= backupTickets = 10 * TICKET_10000; // MAX value( 1 million )
    tickets= backupTickets = 10 * TICKET_1MILLION; // MAX value( 1 million )
#endif // TODO #2
 
    // TASK CREATE
    strcpy(TaskUserData[TASK_1_ID].TaskName, "Task1");
    OSTaskCreateExt(Task1,
                    (void *)0,
                    &Task1Stk[TASK_STK_SIZE - 1],
                    TASK_1_PRIO,
                    TASK_1_ID,
                    &Task1Stk[0],
                    TASK_STK_SIZE,
                    &TaskUserData[TASK_1_ID],
                    0);
    if (err) printf("OSTaskCreate error found, code[0x%X]\n",err);
 
    // TASK CREATE
    strcpy(TaskUserData[TASK_2_ID].TaskName, "Task2");
    OSTaskCreateExt(Task2,
                    (void *)0,
                    &Task2Stk[TASK_STK_SIZE - 1],
                    TASK_2_PRIO,
                    TASK_2_ID,
                    &Task2Stk[0],
                    TASK_STK_SIZE,
                    &TaskUserData[TASK_2_ID],
                    0);
    if (err) printf("OSTaskCreate error found, code[0x%X]\n",err);
 
    /* delete self task */
    err = OSTaskDel(OS_PRIO_SELF);
    if (err) printf("OSTaskDel(OS_PRIO_SELF) error found, code[0x%X]\n",err);
}
 
//
// 태스크 1
//
void Task1(void *pdata)
{
    INT8U err;
    
    pdata = pdata;                /* 컴파일러 경고를 막기 위함 */
 
    printf("\n\nTask1 TASK created,\n");
 
    while(1) {
        if(buyTicket() <= 0)
        {
            T1_Ticket++;
//            printf("[TASK1]COUNTER up to %d\n", T1_Ticket);
            /* delete other task */
            err = OSTaskDel(TASK_2_PRIO);
            break;
        }
        T1_Ticket++;
    /* TODO #1: 
        OSTimeDly() 시간 지연을 적당히 입력하여 티켓 카운트 수가 
        오류가 나도록 만든다 */
#if 1 // No comment
        OSTimeDly(2);    // 주의사항! 2 이상의 값을 입력 할 것
#endif // TODO #1
    }
 
    // 1초마다 콘솔 출력 '중지'
    USE_OSTimeTickHook = 0// refer to 'OS_CPU_C.C'
 
    printf("\n[TASK1]Total Tickets = %d\n", T1_Ticket + T2_Ticket);
 
    if(backupTickets != T1_Ticket + T2_Ticket)
        printf("Not good. expectation(%d)\n", backupTickets);
    else
        printf("Good!. Matched\n");
 
    /* delete self task */
    err = OSTaskDel(OS_PRIO_SELF);
    if (err) printf("OSTaskDel(OS_PRIO_SELF) error found, code[0x%X]\n",err);
}
 
//
// 태스크 2
//
void Task2(void *pdata)
{
    INT8U err;
    INT32U timeo;
    int i;
 
    pdata = pdata;                /* 컴파일러 경고를 막기 위함 */
 
    printf("Task2 TASK created,\n");
 
    printf("please wait");
 
    // 1초마다 콘솔에 동작중을 표시(.)
    USE_OSTimeTickHook = 1// refer to 'OS_CPU_C.C'
 
    while(1) {
        for(i=0;i<100000;i++)
        {
            if(buyTicket()==0)
            {
                T2_Ticket++;
//                printf("[TASK2]COUNTER up to %d\n", T2_Ticket);
                /* delete other task */
                err = OSTaskDel(TASK_1_PRIO);
                goto exit;
            }
            T2_Ticket++;
        }
        timeo = randomnumber();
        OSTimeDly(timeo % 3);
    }
 
exit:
    // 1초마다 콘솔 출력 '중지'
    USE_OSTimeTickHook = 0// refer to 'OS_CPU_C.C'
 
    printf("\n[TASK2]Total Tickets = %d\n", T1_Ticket + T2_Ticket);
 
    if(backupTickets != T1_Ticket + T2_Ticket)
        printf("Not good. expectation(%d)\n", backupTickets);
    else
        printf("Good!. Matched\n");
 
    /* delete self task */
    err = OSTaskDel(OS_PRIO_SELF);
    if (err) printf("OSTaskDel(OS_PRIO_SELF) error found, code[0x%X]\n",err);
}
 
//
// buyTicket
//
int buyTicket(void)
{
    OS_CPU_SR cpu_sr;
 
    /* TODO #3: 
        OS_ENTER_CRITICAL() 과  OS_EXIT_CRITICAL()을 이용하여 
        공유변수(tickets)를 보호한다 */
#if 1
    // CRITICAL SECTION(ENTER)
    OS_ENTER_CRITICAL();
#endif // TODO #3
 
    tickets --;    // ticket count
 
#if 1
    // CRITICAL SECTION(EXIT)
    OS_EXIT_CRITICAL();
#endif // TODO #3
 
    return(tickets);
}
 
/*-----------------------------------------------------------------------------
 * Program : 03_CRITICAL.C
-----------------------------------------------------------------------------*/
 
cs





* TODO 1

현재 2개의 Task가 동작 중이며 task1과 task2는 다른 속도로 실행되고 있다. 

tickets= backupTickets = 10 * TICKET_1MILLION;

현재 티켓의 수로 실행하면 collision(충돌)이 생겨서 동시성 문제가 발생한다.



* TODO 2


이때 티켓의 수를 줄여보면


tickets= backupTickets = 10 * TICKET_10000;


결과를 보면 횟수가 적으면 충돌가능성도 줄어들게 된다.





* TODO 3


OS_ENTER_CRITICAL();

OS_EXIT_CRITICAL();        함수를 이용해 상호 배제를 한면 횟수가 많아도 동시에 진입하지 않습니다. 

즉, 공유 변수를 보호합니다.

그리고 CRITICAL SECTION(임계 영역) 커널 서비스를 자주 호출 하게 되면 그렇지 않을 경우보다 시간이 많이 소요됩니다.






*Critical Section(임계 영역) : 공유 자원을 사용 중인 함수내의 일부 혹은 전체 영역
이 코드의 영역의 실행이 시작되면 적어도 다른 태스크가 이영역을 선점하여 실행하는 일이 없어야 안전합니다.

상호 배제 방법 1. 인터럽트 작동을 잠금
   2. 스케줄링 중단
   3. 세마포어류의 커널서비스    ->많이 사용하는 방법
   4. 공유 자원을 사용하지 않는다(상호배제 사용 x) ->가장 이상적인 방법.

예) 전역변수를 쓰지 않는다.

1
2
3
4
5
6
7
8
int Temp; //전역변수
 
void swap(int *x,int *y)
{
    Temp = *x;
    *= *y;
    *= Temp;
}

cs

    <재진입이 불가능한 경우>

  ▼

1
2
3
4
5
6
7
void swap(int *x,int *y)
{
    int Temp;
    Temp = *x;
    *= *y;
    *= Temp;
}
cs

        <재진입이 가능한 경우>















'RTOS' 카테고리의 다른 글

[RTOS_Day5]RTOS 포팅 진행 기록_2  (0) 2018.12.27
[RTOS_Day4]RTOS 포팅 진행 기록  (0) 2018.12.26
[RTOS_Day3]통계 테스크  (0) 2018.12.19
[RTOS_Day2]시간관리 함수  (2) 2018.12.18
[RTOS_Day1]테스크 생성 및 운용  (0) 2018.12.17

+ Recent posts