[2024.10.28] 필수 온라인 강의 Part4 시스템 프로그래밍 CH03 프로세스와 스레드 다루기
프로세스 다루기
프로세스 복습 - https://glowdp.tistory.com/36 - 프로세스란 실행 중인 프로그램 ⇐ 같은 프로그램도 별도의 프로세스가 될 수 있다 - 프로그라운드 프로세스 & 백그라운드 프로세스 - 프로세스 제어 블록 (PCB)을 통해서 특정 정보( PID (PPID), 레지스터, 스케줄링 정보, 메모리 정보, 사용한 파일 정보, 입출력장치 정보 )를 식별 - 대표적인 프로세스 상태 : 생성, 준비, 실행, 대기, 종료 - 리눅스 프로세스 상태 확인 : R(실행), S(대기), W(준비), S(종료), Z(좀비) - 계층적인 구조
함수 명의 알파벳 - 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 - 없음
뮤텍스 락 여부 확인
Parameter - mutex: mutex instance Return - 성공시 0 - 실패시 errno * 다른 스레드가 lock을 점유했을 경우 - lock(): sleep à lock을 점유했을 때 리턴 - trylock(): 곧바로 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
unnamed & named semaphore - 세마포 자원 요청 : 공유 자원에 접근할 임계 구역을 실행하고 싶을 때
Parameter - sem: 요청할 세마포 객체 Return - 성공시 0 - 실패시 -1 : semaphore value 1 감소, 0 이하일 경우 block
- 세마포 자원 요청 시도 : blocking 없이 자원 요청, 즉시 반환
Parameter - sem: 요청할 세마포 객체 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
시그널 다루기
시그널이란 - 소프트웨어 인터럽트 - 프로세스에게 특정 이벤트가 발생했음을 알리는 수단 - 다양한 시그널이 있고, 시그널 종류별로 번호가 할당되어 있음 - 시그널마다 기본 동작이 정해져 있고, 처리가 가능한 것들이 있음.(무시도 처리의 일부)
대표적인 시그널 - 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으로 지정된 시그널은 시그널 핸들러를 한 번만 실행, 그 다음부터는 기본 동작 등