jun-wiki

View My GitHub Profile

Posts (Latest 10 updated) :
Read all
Contents:
  1. 왜 필요한가?
  2. 구현
    1. 구조
    2. 라이프 사이클
      1. (A) 자식 생성 시
      2. (B) 자식 종료 시
      3. (C) 부모의 wait(tid) 구현
    3. 동기화/수명 관리
      1. 부모 스레드를 자식이 알 필요 없는 이유

Pintos 구현하며 자식 프로세스 만들때 필요한 구조체와

라이프 싸이클 정리해보려한다

별 거 아닌 거 같은데 모르면 못하는 내용 같아 확실히 정리해두는게 목표다

̗̀( ˶^ᵕ'˶)b

(감사인사는 접어두도록)


스레드의 ⌜핵심⌟ 이라

자식과 부모간 동기화 하는 법과 필요한 이유 등 가능한거 다 서술한 계획이다


왜 필요한가?

생각보다 필요하다

자식과 부모는 별도 프로세스라 사실 서로를 알아볼 방법이 없다

최소한 서로에 대한 기록이 있어야하기에

이를 위한 구조체를 만들어주고 인자도 넣어줘야 한다


구현

구현한 방식과 유의점 적어 놓을 거다

ദ്ദിˊᗜˋ)


구조

/* thread.h에 넣든지 process.h에 넣든지 하면 된다 */
/* 자식 상태 */
struct child_status {
  tid_t tid;
  int exit_code;            // 자식 종료 코드
  bool exited;              // 종료 여부
  bool waited;              // 부모의 wait() 호출 여부
  int ref_cnt;              // parent + child = 2 로 시작, 소유 카운트
  struct semaphore sema;    // parent가 wait()에서 대기, 부모 wait일시 down, 자식 exit시 up
  struct list_elem elem;    // parent->children 에 매달림, 부모의 children list 용
};

/* struct thread.h의 thread다 */
struct thread {
  tid_t tid;

  struct list children;            // struct child_status 노드들의 리스트
  struct child_status *my_status;  // 내가 종료시 업데이트할 내 노드
  /* ...나머지 필드들 */
};
  • tid: 부모가 wait으로 자식 찾을 때 키

  • exit_code: 자식이 종료 시 남기는 값 (sys_exit(status), 비정상 종료 )

  • exited: 자식이 종료했음을 표시

  • waited: 부모가 wait했는지 확인해 중복 wait방지

  • ref_cnt: 수명 관리

    • 생성 시 2로 시작 (부모 + 자식)

    • 자식이 process_exit()에서 --ref_cnt후 0이면 free(cs)

    • 부모가 wait() 처리 끝내고 리스트에서 제거 후 --ref_cnt하고 0이면 free(cs)

  • sema: 동기화의 핵심 (사실 구조체 인자 전부 핵심이긴 하다 ( • ᴗ - ) ✧ )

    • wait()에서 sema_down()
      ->자식이 종료하면 sema_up()로 깨움
  • elem: 부모의 children리스트 사용을 위해


부모 리스트는 딱히 만들 필요 없다는 것에 유의하자

ദ്ദി(。•̀ ᗜ<)


라이프 사이클

(A) 자식 생성 시

  1. struct child_status *cs = malloc(...)
cs->tid = child_tid;
cs->exit_code = -1;   // 기본값 -1 권장
cs->exited = false;
cs->waited = false;
cs->ref_cnt = 2;
sema_init(&cs->sema, 0);
list_push_back(&parent->children, &cs->elem);
  1. 자식 스레드/프로세스 시작 직후
thread_current()->my_status = cs;
thread_current()->parent    = parent;
thread_current()->ppid      = parent->tid; // (옵션)

(B) 자식 종료 시

struct thread *cur = thread_current();
struct child_status *cs = cur->my_status;

cs->exit_code = status;  // 또는 커널이 정한 에러 시 -1
cs->exited = true;
sema_up(&cs->sema);      // wait() 중인 부모를 깨움

if (--cs->ref_cnt == 0) free(cs);

(C) 부모의 wait(tid) 구현

  1. childred 리스트를 tid로 선형 탐색cs(자식 상태)를 찾는다. 없으면 -1

  2. cs->waited가 이미 true면 -1 (중복 wait 막기 이를 위해 구조체에 그거 만들어 놓은 거다)

  3. cs->waited = true;

  4. sema_down(&cs->sema); 자식이 아직이면 여기서 잔다 (⸝⸝ᴗ﹏ᴗ⸝⸝) ᶻ

  5. 깨어나면 exit_code를 얻는다

  6. 부모의 childred 리스트에서 cs제거

list_remove(&cs->elem);
if (--cs->ref_cnt == 0) free(cs);
return exit_code;
  1. 수명 깍고 free 해야하는지 체크 및 exit_code 반환



동기화/수명 관리

  • 세마포어가 잘 해줘서 뭐 더 필요없다   - ̗̀( ˶^ᵕ’˶)b

  • ref_cntfree 한번으로 통제해서 더블프리 같은거 방지

  • 자식은 my_status만, 부모의 childred 리스트는 건들지 않아 OK
    자식은 sema_up만 호출, 리스트 삽입/삭제 모두 부모측

  • 동일 리스트 건들 리 없으니 락없어도 bb


부모 스레드를 자식이 알 필요 없는 이유

동기화와 결과 전달 모두 child_status에서 처리 (자식 쪽)

  • 자식: my_status->exit_code 설정 후 sema_up()
  • 부모: children에서 tid로 찾고 sema_down()exit_code 읽고 정리

child_status를 공유하는 법이 뭐길래?

힙으로 독립 객체 생성한다

  • 부모는 자기 childred 리스트에 elem으로 소유 1
  • 자식은 my_status 포인터로 소유 1

그렇기에 부모-자식만 공유해 문제 X

자식이 또 자식으로 만들어도 서로 간섭이 안 일어나는 이유가 여기 있다
차피 자식 더 만들어도 새로운 간선을 만드는 거라 말이다 ദ്ദി(。•̀ ,<)~✩‧₊