Study/CS 기초

시스템 프로그래밍 - 프로세스와 스레드

김 도경 2024. 10. 28. 14:33

[2024.10.28] 필수 온라인 강의 Part4 시스템 프로그래밍 CH03 프로세스와 스레드 다루기

프로세스 다루기
  • 프로세스 복습
       - https://glowdp.tistory.com/36
       - 프로세스란 실행 중인 프로그램 ⇐ 같은 프로그램도 별도의 프로세스가 될 수 있다 
       - 프로그라운드 프로세스 & 백그라운드 프로세스
       - 프로세스 제어 블록 (PCB)을 통해서 특정 정보( PID (PPID), 레지스터,  스케줄링 정보, 메모리 정보, 사용한 파일 정보, 입출력장치 정보 )를 식별
       - 대표적인 프로세스 상태 : 생성, 준비, 실행, 대기, 종료
       - 리눅스 프로세스 상태 확인 : R(실행), S(대기), W(준비), S(종료), Z(좀비)
       - 계층적인 구조
        
  • fork 시스템 호출 
    Parameter
       - 없음

    Return
        - 성공시 (부모 프로세스의 경우) 자식 프로세스의 PID, (자식 프로세스의 경우) 0
        - 실패시 (부모 프로세스의 경우) -1, (자식 프로세스의 경우) 미생성

  • exec
      - 새로운 프로그램으로 프로세스 메모리를 채우기

    함수 명의 알파벳
    - l: 리스트 형식으로 인자 전달 (arg0, arg1, ... , NULL)
    - v: 벡터(문자열) 형식으로 인자 전달
    - p: 기본 환경 변수($PATH)에서 찾음
    - e: 새로운 환경 변수 설정 가능

    Return - 성공시 리턴 없음 - 실패시 -1
스레드 다루기

 

  • 스레드
         - 프로세스를 구성하는 실행 흐름의 단위
         - 각기 다른 스레드 ID, 프로그램 카운터, 레지스터, 스택

  • 가장 주된 차이점은 자원 공유 여부
         - 프로세스 간에는 기본적으로 자원을 공유하지 않음
              - 프로세스 간에도 자원 공유가 가능하다! → 프로세스간 통신 (IPC; Inter-Process Communication)
                     - 공유 메모리를 통한 통신
                     - 파이프를 통한 통신
                     - 네트워크 소켓을 통한 통신
                     - 스레드 간에는 프로세스의 자원을 공유
  • 스레드 생성
         - Parameter
               - thread: 스레드 ID가 저장될 곳
               - attr: 스레드 속성 (NULL일 경우 기본 속성으로 초기화)
                        - pthread_attr_t 구조체
                        - pthread_attr_init() – 스레드 속성 초기화
                        - pthread_attr_destroy() - 스레드 속성 폐기
                        - 스택 크기, 스케줄링 인자, 최초 detach 상태 등 대부분 NULL로 지정
                        - https://docs.oracle.com/cd/E19455-01/806-5257/6je9h032j/index.html
               - start_routine: 스레드가 실행할 대상
               - arg: 스레드 실행시 사용할 인자
         - Return
              - 성공시 0, 실패시 errorno


  • 종료 처리: 스레드 조인(join)과 떼어내기(detach)
    스레드 조인: 스레드 실행이 종료될 때까지 대기 (스레드 종료 처리)
         - Parameter
              - thread: 기다릴 스레드 ID
              - retval: 스레드의 종료 상태(exit status) 저장
         - Return
              - 성공시 0, 실패시 errorno

    스레드 떼어내기: 종료 시 자동으로 자원 해제
        - Parameter
              - thread: 떼어낼 스레드 ID
         - Return
              - 성공시 0, 실패시 errorno
          * detach된 스레드는 말 그대로 떨어져있는 실행 단위, 실행이 끝날 시간 or 보장이 필요하다

    스레드 종료
         - Parameter
              - retval: 스레드의 종료 상태(exit status) 저장
         - Return
              - 없음
뮤텍스와 세마포
  • 동기화 복습 – 공유 자원과 임계 구역 : https://glowdp.tistory.com/38
  • 뮤텍스 복습: 상호 배제를 위한 동기화

  • 뮤텍스 초기화 (두 가지 방법)
    Parameter
            - mutex: mutex instance
           - attr: mutex 속성 (일반적으로 NULL, NULL로 초기화할 경우 하단 초기화 구문과 같음)
    Return
           - 성공시 0
          - 실패시 errno

  • 뮤텍스 락/언락
    Parameter
              - mutex: mutex instance
    Return
              - 성공시 0 - 실패시 errno
  • 뮤텍스 락 여부 확인
    Parameter
             - mutex: mutex instance
    Return
            - 성공시 0 - 실패시 errno
    * 다른 스레드가 lock을 점유했을 경우
          - lock(): sleep à lock을 점유했을 때 리턴
          - trylock(): 곧바로 errno 리턴 후 코드 진행
  • 뮤텍스 삭제
    Parameter
            - mutex: mutex instance
    Return
           - 성공시 0 - 실패시 errno


  • 세마포
        - unnamed semaphore
             - 공유 메모리에 대한 동기화 수행 시 활용
             - 공유 메모리의 일부를 세마포로 간주, 접근
             - sem_init(), sem_destroy()
        - named semaphore
             - 일반적인 자원에 대한 동기화 수행 시 활용
             - (세마포에 ID를 부여) 세마포를 파일과 같이 간주, 접근
             - sem_open(), sem_close(), sem_unlink()
        - unnamed semaphore & named semaphore
             - sem_wait(), sem_trywait(), sem_timedwait(), sem_post()
  • unnamed semaphore
       - 초기화
    Parameter
             - sem: 초기화할 세마포 객체 포인터
             - pshared: 공유 옵션 (0일 경우 프로세스 내 스레드 간 공유, 1일 경우 프로세스 간 공유)
             - value: 세마포 초기값
    Return
             - 성공시 0 - 실패시 -1

       - 해제
    Parameter
            - sem: 해제할 세마포 객체
    Return
           - 성공시 0 - 실패시 -1

  • named semaphore
    - 생성/열기
    Parameter
          - name: 세마포 ID (슬래시로 시작: e.g. /sempahoreid)
          - oflag: O_CREAT(세마포 생성) 혹은 O_EXCL(중복된이름의 세마포 체크)
          - mode: 권한 - value: 세마포 초기값

    Return
          - 성공시 sempahore 포인터
          - 실패시 SEM_FAILED

    - 닫기
    Parameter
           - sem: 닫을 세마포 객체
    Return
          - 성공시 0 - 실패시 SEM_FAILED

    - 삭제
    Parameter
            - name: 삭제할 semaphore 객체
    Return
            - 성공시 0
            - 실패시 SEM_FAILED
    * 모든 프로세스가 semaphore를 닫아야 삭제

  • unnamed & named semaphore
    - 세마포 자원 요청 : 공유 자원에 접근할 임계 구역을 실행하고 싶을 때
    Parameter
         - sem: 요청할 세마포 객체
    Return
         - 성공시 0 - 실패시 -1
     : semaphore value 1 감소, 0 이하일 경우 block

    - 세마포 자원 요청 시도 : blocking 없이 자원 요청, 즉시 반환
    Parameter
          - sem: 요청할 세마포 객체
    Return
         - 성공시 0 - 실패시 -1

    - 세마포 자원 요청 시도 (타임아웃 조건부)
    Parameter
       - sem: 요청할 세마포 객체
       - abs_timeout: timeout 설정값
    Return
       - 성공시 0 - 실패시 -1

    - 세마포 자원 해제
    Parameter
             - sem: 자원을 해제할 semaphore 객체
    Return
              - 성공시 0 - 실패시 -1
공유 메모리 기반 IPC
  • 공유 메모리?
        - 다수의 프로세스가 공유 가능한 메모리 영역
        - 공유하는 메모리를 읽고 씀으로써 프로세스간 통신이 가능
            * [mmap을 이용한 파일 매핑]도 공유 메모리 기반 IPC의 예시

  • 공유 메모리 열기/생성하기
    Parameter
            - name: "슬래시로 시작하는" 공유 메모리 이름 (e.g. /myshm)
            - oflag: 플래그 설정 - mode: 권한 설정
    Return
           - 성공시 공유 메모리 descriptor - 실패시 -1
  • 공유 메모리 삭제하기
    Parameter
            - name: "슬래시로 시작하는" 공유 메모리 이름 (e.g. /myshm)
    Return
            - 성공시 0 - 실패시 -1

 

파이프 기반 IPC
  • pipe란
          - 단방향 IPC 도구
          - 한 쪽에서는 파이프를 읽고, 한 쪽에서는 파이프에 쓴다
          - 주로 Stream 형태의 데이터를 주고받을 때 사용
          - 파이프는 일종의 파일: file descriptor를 기반으로 읽고 쓰기 수행

          - 파이프에 더 이상 쓸 공간이 없을 때 쓰면 block
          - 파이프가 비어 있을 때 읽기를 시도하면 block
          - 지나치게 큰 값(리눅스의 경우 4KB 이상) 쓰기 지양 : 쪼개져서 전달-데이터 손실

  • 파이프 생성
    Parameter
         - pipefd[2]: pipe 디스크립터를 저장할 버퍼 (pipefd[0] == 읽기측 디스크립터, pipefd[1] == 쓰기측 디스크립터)
    Return
         - 성공시 0 - 실패시 -1

  • 파이프 읽고 쓰기
    Parameter
          - pathname: 파일 경로, flag: 접근 플래그, mode: 파일 생성시 모드
    Return
         - 성공시 파일 디스크립터 - 실패시 -1

  • 파이프 열고 닫기
    Parameter
           - pathname: 파일 경로,
           - flag: 접근 플래그
                  - O_RDONLY : 읽기 전용으로 열기
                  - O_WRONLY: 쓰기 전용으로 열기
                  - O_RDWR : 읽기 쓰기 전용으로 열기
                  - O_CREAT : 파일이 없다면 생성하기 (mode 필수)
                  - O_TRUNC: 기존 파일 내용 삭제
                  -O_APPEND : 파일의 끝 지점부터 쓰기 시작 (추가하기)
           - mode: 파일 생성시 모드
                  - S_IRWXU : 소유자에 대한 읽기, 쓰기, 실행권한 모두 설정
                  - S_IRUSR : 소유자에 대한 읽기 권한
                  - S_IWUSR : 소유자에 대한 쓰기 권한
                  - S_IXUSR : 소유자에 대한 실행 권한
                  - S_IRWXG : 그룹에 대한 읽기, 쓰기, 실행권한 모두 설정
                  - S_IRGRP : 그룹에 대한 읽기 권한
                  - S_IWGRP : 그룹에 대한 쓰기 권한
                  - S_IXGRP : 그룹에 대한 실행 권한
                  - S_IRWXO : Other에 대한 읽기, 쓰기, 실행권한 모두 설정
                  - S_IROTH : Other에 대한 읽기 권한
                  - S_IWOTH : Other에 대한 쓰기 권한
                  - S_IXOTH : Other에 대한 실행 권한
    Return
           - 성공시 파일 디스크립터 - 실패시 -1

  • 파이프 열고 닫기
    Parameter
          - fd: 닫고자 하는 파일 디스크립터
    Return
          - 성공시 0 - 실패시 -1

  • 양방향 통신시 주의: 필요없는 fd는 닫아야 한다

 

  • named pipe
       - 이름 있는 파이프
       - 여기서의 ‘이름’ == 파일 <-사실상 파일 입출력
       - 파일의 경로를 ID 삼아 파이프 특정 짓기 가능
       - 파이프 open 시 읽기 측과 쓰기 측이 동시에 개방

  • named pipe 생성
    Parameter
          - pathname: 생성할 named pipe 파일 경로
          - mode: 권한 설정
    Return
         - 성공시 0 - 실패시 -1

시그널 다루기
  • 시그널이란
        - 소프트웨어 인터럽트
        - 프로세스에게 특정 이벤트가 발생했음을 알리는 수단
        - 다양한 시그널이 있고, 시그널 종류별로 번호가 할당되어 있음
        - 시그널마다 기본 동작이 정해져 있고, 처리가 가능한 것들이 있음.(무시도 처리의 일부)

  • 시그널 이란
    - https://man7.org/linux/man-pages/man7/signal.7.html   
    - https://docs.python.org/3/library/signal.html
    - ibm.com/docs/en/ztpf/2019?topic=ztpf-family-products-end-service-versions

  • 대표적인 시그널
    - SIGCHLD: Child stopped or terminated : 자식프로세스 멈추고 터미널됨
    - SIGILL: Illegal Instruction : 
    - SIGINT: Interrupt from keyboard (Ctrl+C)
    - SIGKILL: Kill signal (처리 불가능)
    - SIGSEGV: Invalid memory reference
    - SIGTERM: Termination signal (처리 가능)
    - SIGUSR1: User-defined signal 1
    - SIGUSR2: User-defined signal 2
    - SIGCONT: Continue if stopped
    - SIGSTOP: Stop process

  • 특정 프로세스 (그룹)에게 시그널 보내기
        - 프로세스 그룹 : https://en.wikipedia.org/wiki/Process_group
    Parameter
      - pid: 시그널을 보낼 대상
             >= 1 : PID
             == 0 : 프로세스 그룹 모두에게 전송
             == -1 : 권한이 허락하는 한 모든 프로세스
             < -1 : 프로세스 그룹 아이디가 (-pid)인 프로세스 그룹 전체
      - sig: 전송할 시그널 번호
    Return
      - 성공시 0 - 실패시 -1

  • 자기 자신에게 시그널 보내기
    Parameter
          - sig: 전송할 시그널 번호
    Return
          - 성공시 0 - 실패시 -1

  • 시그널 처리
    Parameter
          - signum: 처리할 시그널 번호
          - handler: 시그널 핸들러(시그널이 동작하는 방법)
    Return
          - 성공시 이전 시그널 핸들러 (언제든 이전 시그널 설정으로 돌아갈 수 있도록)
          - 실패시 SIG_ER


  • 심화) 시그널 집합 관리: 시그널 마스킹
    Parameter
         - signum: 처리할 시그널 번호 (SIGKILL, SIGSTOP 적용 불가)
         - act: 지정한 시그널에 대해 취해야할 정보
         - oldact: 이전에 지정되어 있었던 시그널 처리 정보
    Return
         - 성공시 0
         - 실패시 -1

  • sa_handler: 시그널 핸들러
    - signum에 해당하는 시그널이 들어왔을 때 취해야 할 행동
         - SIG_DFL: 기본 동작
         - SIG_IGN: 무시 (SIGSTOP, SIGKILL 제외)
         - 함수 포인터 (사용자가 지정한 함수 주소)
         -  sa_flags가 SA_SIGINFO로 지정되어 있다면
         - sa_sigaction 실행 시그널 번호 뿐 아니라 시그널을 보낸 프로세스의 PID 등 다양한 정보를 알 수 있음 보통
         - sa_handler, sa_sigaction 둘 중 하나만 사용토록 권장
         - sa_mask: 시그널 마스크 시그널 핸들러가 실행되는 동안 봉쇄(처리 연기)할 시그널들 실행 중인 핸들러가 종료되면 그 때 처리
         - sa_flags: 시그널 플래그 시그널 처리 절차에서 참조할 플래그 e.g.
         - SA_SIGINFO: sa_handler 대신 sa_sigaction 실행
         - SA_ONESHOT: signum으로 지정된 시그널은 시그널 핸들러를 한 번만 실행, 그 다음부터는 기본 동작 등

'Study > CS 기초' 카테고리의 다른 글

데이터베이스 거시적으로 보기  (1) 2024.10.30
소켓 프로그래밍  (0) 2024.10.29
시스템 프로그래밍 - 오리엔테이션  (1) 2024.10.22
네트워크 - 응용 계층  (2) 2024.10.22
네트워크 - 전송 계층  (4) 2024.10.22