[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 |