일상기록장/크래프톤 정글 일지

Week 7. PintOS 프로젝트 1(Threads) 회고

hyuga_ 2023. 12. 3. 18:42

대망의 핀토스 주차..! 정글에 들어오기 전부터 커리큘럼에서 가장 큰 특징점이라 생각했고, 또 나만무를 제외하면 가장 기대했던 기간이다. 뭔가 핀토스 하면 전공자들 사이에서도 나름 악명높고 인증받은 프로젝트이기에, 그만큼 이 기간을 잘 지나가면 '넌 개발자 해도 돼'라는 심리적 징표를 얻게되는 것 같았기 때문이다. 실제로 해보니 그냥 교과서를 읽어보는 걸 넘어서 실제 OS의 동작을 설계하고 구현해보는 경험은 정말 특별한 것 같다. 전공자가 아니면 하기 힘든 경험을 하기 위해 들어왔기 때문에 매우 만족스럽다. 

 

11월 23일에 핀토스 프로젝트가 시작되었고, 프로젝트 1을 마무리한 오늘은 정확히 10일차이다. 걱정도 많았고 실제로도 쉽지 않았지만 그래도 아직까지는 어찌어찌 잘 헤쳐온 것 같다. 근데 정말로 정신없었고 미니 프로젝트 이후로 오랜만에 철야를 다시 하게되었다 ..🥲 다음 프로젝트에 비하면 이번주는 쉬운편이었다는 코치님이 말씀이 살짝 걸리긴 하네. ㅎ

 

 

 

 

OSTEP을 읽다가 재밌었던 내용. 컴퓨터 문제가 생기면 컴잘알들이 '재부팅 해~' 라고 하는게 그냥 하는 말이 아니었던..

 

 

 

 

인생에 적용하고 싶다는 내 친구

 

 

 

 

 

디버거가 아직 낯선 나는 여전히 printf가 너무 좋다...


이번주 배운 것

  • 프로그래밍
    • 수만 라인의 프로그램을 열심히 파보고 분석해보는 경험
    • 그 과정에서 미친듯이 밀려오는 버그들을 잡아보는 경험
    • 설계에 공을 많이 들일수록 코딩이 더 수월하고 재미있다. 수정도 비교적 빨라진다. 
  • CS 지식
    • 타이머 인터럽트의 존재, 쓰레드의 상태 변화의 원리
    • 스케줄링을 왜 하는가?
    • 대표적인 스케줄링 기법들 
    • 동기화(Synchronization)가 왜 필요한가?
    • 대표적인 동기화 기법들

 

더 알아보고 싶은 것

  • 아직 디버거 활용에 익숙치 않은 것 같다.
  • 인터럽트 핸들러에 대해서 더 파보고 싶다! 코드를 짜다보면 인터럽트를 꺼주고 다시 켜주고.. 또 외부 인터럽트가 작동하고 있는 중에 인터럽트를 발생시키면 Assert에 걸리는데 이 전체적인 맥락과 동작 과정이 궁금하다. 근데 정글 수료 전까지 시간이 날지 잘 모르겠다. (아마 없을 것 같다ㅎ)

 

개인 목표 체크

1. 매주 과제 완수율 90% 이상 달성하기 ✅ (98%!!)
2. 주 3회 이상 운동하기 ❌ 
3. 공부 내용 기록하기
4. 주 3회 이상 알고리즘 

 

ㅋㅋㅋㅋㅋ 극단적이네..

 

공부 내용 기록하기에 X 표시한 이유는 너무 바빠서 기록하지 못한 내용이 너무 많기 때문이다.

 


7주차 퀴즈

1. 응용프로그램을 구현할 때 multi process와 multi thread 중 하나를 선택하는 기준은 어떤 것이 있는지 몇 가지 제시하세요.

2. 데드락을 해결하기 위한 전략을 두 가지 이상 설명하십시오.

3. Semaphore와 Mutex의 특징과 주요 차이점은 무엇인가요?

4. 다음 ANSI C프로그램에서 출력되는 내용은 무엇인가요?

#include <stdio.h>

int f(int x, int *py, int **ppz)
{
    int y, z;
    **ppz += 1;
    z = **ppz;
    *py += 2;
    y = *py;
    x += 3;
    return x + y + z;
}

int main()
{
    int c, *b, **a;
    c = 4;
    b = &c;
    a = &b;
    printf("%d\n", f(c, b, a));
    return 0;
}

 

5. 다음 C 코드에서 발생하는 메모리 누수(memory leak)를 찾고, 해결방안을 제시하세요.

#include <stdio.h>
#include <stdlib.h>

typedef struct {
    int data;
    char *description;
} item;

item* create_item(int data, const char *desc) {
    item *new_item = (item *)malloc(sizeof(item));
    
    if (new_item == NULL) {
    	return NULL;
	}

    new_item->data = data;
    new_item->description = (char *)malloc(strlen(desc) + 1);
    strcpy(new_item->description, desc);
    
    return new_item;
}

int main() {
    item *myItem = create_item(5, "Test Item");
    printf("Item: %d, Description: %s\n",
    	myItem->data, myItem->description);
    
    // 다른 작업 수행
    
    free(myItem); // 메모리 해제
    return 0;
}

 

 

 

 

 

 

 

퀴즈 답

더보기

 

1. Multi-Process vs. Multi-Thread 선택 기준

Multi-Process와 Multi-Thread 선택 시 고려해야 할 몇 가지 기준은 다음과 같습니다:

- 자원 공유: 
  - Multi-Thread는 메모리와 자원을 공유하기 때문에 통신이 용이하지만, 자원 관리에 주의해야 합니다.
  - Multi-Process는 각각 독립된 메모리 공간을 가지므로 자원 공유가 덜하지만, 프로세스 간 통신(IPC)이 더 복잡합니다.

- 안정성과 격리성: 
  - Multi-Thread는 한 스레드의 오류가 전체 프로세스에 영향을 미칠 수 있습니다.
  - Multi-Process는 각 프로세스가 독립적이므로 한 프로세스의 실패가 다른 프로세스에 영향을 덜 미칩니다.

- 메모리와 오버헤드:
  - Multi-Thread는 적은 메모리 공간을 사용하고 컨텍스트 전환 시 오버헤드가 적습니다.
  - Multi-Process는 더 많은 메모리와 높은 컨텍스트 전환 비용이 발생합니다.

- 개발과 디버깅의 용이성:
  - Multi-Thread 개발은 동기화와 같은 복잡한 문제를 다루어야 하므로 더 어려울 수 있습니다.
  - Multi-Process는 독립적인 실행 흐름을 가지므로 디버깅이 상대적으로 간단할 수 있습니다.

2. 데드락 해결 전략

데드락을 해결하기 위한 전략은 다음과 같습니다:

- 예방: 데드락의 네 조건(상호 배제, 비선점, 점유 대기, 순환 대기) 중 하나 이상을 제거하여 데드락 발생을 예방합니다.
- 회피: 자원 할당 시 시스템의 상태를 검사하여 데드락이 발생할 가능성이 있는 경우 자원을 할당하지 않습니다. 예를 들어, 은행원 알고리즘(Banker's Algorithm)이 이에 해당합니다.
- 감지 및 회복: 데드락이 발생했을 때 이를 감지하고, 예를 들어 프로세스를 종료하거나 자원을 강제로 회수하는 방법으로 회복합니다.
- 자원 할당 순서 정의: 모든 자원에 순서를 부여하고, 프로세스가 낮은 순서에서 높은 순서의 자원을 요청하는 방식으로 순환 대기 조건을 방지합니다.

3. Semaphore와 Mutex

- Semaphore:
  - 카운팅 세마포어는 자원의 개수를 나타내며, 여러 스레드가 동시에 자원에 접근할 수 있습니다.
  - 세마포어는 신호(signal)과 대기(wait) 연산을 사용하여 자원의 상태를 관리합니다.

- Mutex:
  - 상호 배제(Mutex)는 한 번에 하나의 스레드만 특정 자원에 접근할 수 있게 합니다.
  - Mutex는 잠금(lock)과 해제(unlock) 연산을 사용하여 자원에 대한 접근을 제어합니다.

- 주요 차이점:
  - Semaphore는 여러 스레드가 동시에 자원을 사용할 수 있도록 할 수 있는 반면, Mutex는 오직 한 스레드만 자원을 사용할 수 있도록 합니다.
  - Mutex는 소유권 개념이 있어 잠금을 건 스레드만이 잠금을 해제할 수 있지만, Semaphore는 소유권이 없어 어떤 스레드든 신호를 보낼 수 있습니다.

4. ANSI C 프로그램 출력


```
#include <stdio.h>
int f(int x, int *py, int **ppz) {
    int y, z;
    **ppz += 1; // c = 5
    z = **ppz;  // z = 5
    *py += 2;   // c = 7
    y = *py;    // y = 7
    x += 3;     // x = 7
    return x + y + z; // 7 + 7 + 5 = 19
}
int main() {
    int c, *b, **a;
    c = 4;
    b = &c;
    a = &b;
    printf("%d\n", f(c, b, a)); // 출력: 19
    return 0;
}
```
이 프로그램은 19를 출력합니다.

5. 메모리 누수 문제 및 해결 방안

문제점:
- `create_item` 함수에서 `new_item->description`에 대한 메모리 할당이 있지만, `main` 함수에서 이 메모리를 해제하지 않고 있습니다.

해결 방안:
- `main` 함수에서 `myItem->description`에 대한 메모리 해제를 추가해야 합니다.

수정된 코드:
```
int main() {
    item *myItem = create_item(5, "Test Item");
    printf("Item: %d, Description: %s\n", myItem->data, myItem->description);

    // 다른 작업 수행

    free(myItem->description); // description 메모리 해제
    free(myItem);              // item 구조체 메모리 해제
    return 0;
}
```
이렇게 하면 메모리 누수 문제를 해결할 수 있습니다.