일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
- 컴퓨터네트워크
- zustand
- 동기 함수 내에서 비동기 함수 호출
- 블로그업로드확인
- LazyHGrid
- zustand란
- 리렌더링최적화
- CSS
- react fsd
- 상단 빈공간 제거
- C++
- LazyVGrid
- 페이지이동함수
- 반응형 css
- navigationBar 숨기기
- 비동기함수
- 페이지전환
- GridItem
- react-router-dom
- react상태관리라이브러리
- @observedobject 프로퍼티 래퍼
- @environmentobject 프로퍼티 래퍼
- BFS
- 가로모드끄기
- featured-sliced-design
- react hook
- @published 프로퍼티 래퍼
- SwiftUI Font
- 리액트최적화
- 세로모드끄기
- Today
- Total
leebaek
[UNIX프로그래밍] 8강 - 시그널 본문
- signal
- child proxess의 종료 상태 확인
- signal 보내기
- signal handling
- sigaction의 구조
- signal 사용 예시
- signal 집합 지정
- sa_sigaction()에 의한 signal handling
- 이전의 설정 복원하기
- alarm signal 설정
- signal blocking
- pause 시스템 호출
■ Signal
□ signal : software interrupt
- kernel -> process 로 알리거나, process -> process 로 알림
- 자료 전송 보다는 비정상적인 상황을 알릴 때 사용
ex. program 수행 중 Ctrl-C 를 누르면
- kernel 이 문자 감지하고, 해당 session에 있는 모든 process에게 SIGINT signal을 보냄
- 모든 process는 종료함 ( 단, shell process는 무시함 )
□ signal 처리 방법
- Default action : 기본동작( 종료 / 무시 / 중지 /코어 덤프 -비정상적인 종료일 시, OS에서 프로그램 종료 이유를 알려줌 )
- 무시 ( signal을 받는 프로세스가 signal을 무시함 )
- 지정된 함수 호출
- signal block ( signal을 받음, 당장은 다른 일을 하고 일을 처리한 뒤 block해둔 signal 처리 )
■ Child process의 종료 상태 확인
pid = wait(&status);
if ( WIFEXITED(status)) // 정상 종료
printf("%d\n", WEXITSTATUS(status));
if ( WIFSIGNALED(status)) // 시그널을 받고 종료
printf("%d\n", WTERMSIG(status));
- 매크로 WIFSIGNALED는 자식 프로세스가 신호를 받아 종료되었는지 확인함
- 예를 들어, SIGKILL 또는 SIGINT 등의 신호로 종료된 경우임
- WTERMSIG는 자식 프로세스를 종료시킨 신호 번호를 반환함
- 신호 번호는 각 신호의 정의에 따라 다르며, 예를 들어 SIGKILL은 9, SIGINT는 2임
■ Signal 보내기
□ kill() : 지정한 process나 process group에 signal을 보냄
#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int sig);
- pid: signal을 받게 될 process 지정
- sig: 보낼 signal을 지정
□ signal을 받을 process 또는 process group 지정
- pid > 0 : 해당 id의 proces에게 signal 전달
- pid = 0 : sender와 같은 process group에 속하는 모든 process에게 signal 전달 ( sender도 포함 )
- pid = -1 : uid가 sender의 euid와 같은 모든 proecess에게 signal 전달
- pid < 0 & pid != -1 : process의 group id가 pid의 절대값과 같은 모든 process에게 signal 전달
- 다른 사용자의 process에게 signal을 보내면 -1 return
□ raise() : 호출한 process에 signal을 보냄
#include <signal.h>
int raise(int sig);
■ Signal handling
- default action ( 프로세스 종료 )
- 무시
- 정의된 함수 호출
□ sigaction()
#include <signal.h>
int sigaction(int signo, const struct sigaction *act, struct sigaction *oact);
□ sigaction 지정 : signal 수신 시 원하는 행동을 취할 수 있음
-> 예외 ) SIGSTOP(process의 일시 중단), SIGKILL(process의 종료)의 경우는 별도의 action을 취할 수 없음
□ sigaction의 구조
struct sigaction {
void (*sa_handler)(int); // 기본 신호 처리기 함수
sigset_t sa_mask; // 처리 중 blocking할 신호
int sa_flags; // 신호 처리 동작 옵션
void (*sa_sigaction)(int, siginfo_t *, void *); // 확장된 신호 처리기 함수
}
▷ void (*sa_handler)(int) - 함수 인자에 int signo 필요 ( ex. catchint(int signo) )
- signo를 수신하면 취할 행동 지정
- SIG_DFL : default 행동 ( 종료, 무시 등 )
- SIG_IGN : 신호를 무시
- 사용자 정의 함수 : signal을 받으면 함수로 제어 이동, 함수 실행 후 signal을 받기 직전의 처리 문장으로 return
▷ sigset_t sa_mask
- signal을 처리하는 동안 차단할 signal 집합을 설정함 ( blocking )
▷ int sa_flags
- SA_RESETHAND : 신호를 한번 처리한 후, signal action을 SIG_DFL로 재설정
- SA_SIGINFO : sa_handler 대신 sa_sigaction을 사용하도록 설정
■ Signal 사용 예
#include <signal.h>
#include <stdio.h>
int main() {
static struct sigaction act;
void catchint(int);
act.sa_handler = catchint;
sigaction(SIGINT, &act, NULL);
printf("sleep call1\n");
sleep(1);
printf("sleep call2\n");
sleep(1);
printf("exiting\n");
exit(0);
}
void catchint(int signo) {
printf("\n CATCHINT: signo=%d\n", signo);
}
- SIGINT를 무시
act.sa_handler=SIG_IGN
sigaction(SIGINT, &act, NULL);
- SIGINT시 종료
act.sa_handler = SIG_DFL;
sigaction(SIGINT, &act, NULL);
- 여러개의 signal을 무시
act.sa_handler = SIG_IGN;
sigaction(SIGINT, &act, NULL);
sigaction(SIGQUIT, &act, NULL);
- 핸들러로 지정된 함수 호출하는 것을 알 수 있음
- Ctrl-C 무시하고 프로그램이 돌아가는 것을 알 수 있음
- Ctrl-C 프로세스가 종료되어 exiting까지 출력되지 않음
■ Signal 집합 지정
□ signal 집합 지정
- sigemptyset -> sigaddset
- sigfillset -> sigdelset
#include <signal.h>
int sigemptyset(sigset_t *set); // 빈 신호 집합 생성
int sigfillset(sigset_t *set); // 신호 집합에 모든 신호 추가
int sigaddset(sigset_t *set, int signo); // 특정 신호를 집합에 추가
int sifdelset(sigset_t *set, int signo); // 특정 신호를 집합에서 제거
int sigismember(sigset_t *set, int signo); // 특정 신호가 집합에 포함되어있는지 확인
sigset_t mask1, mask2;
sigemptyset(&mask);
sigaddset(&mask1, SIGINT);
sigaddset(&mask1, SIGQUIT);
siggillset(&mask2);
sigdelset(&mask2, SIGCHLD);
■ sa_sigaction()에 의한 signal handling
□ act.sa_flags = SA_SIGINFO 설정
- 시그널과 관련된 추가 정보를 받을 수 있어 복잡한 시그널 처리나 디버깅에 유용
#include <signal.h>
#include <stdio.h>
void handler(int signo, siginfo_t *sf, void *uc);
int main() {
static struct sigaction act;
act.sa_flags = SA_SIGINFO;
act.sa_sigaction = handler;
sigaction(SIGINT, &act, NULL);
sleep(3);
raise(SIGUSR1); // 현재 프로세스에 SIGUSR1 신호를 보냄
}
void handler(int signo, siginfo_t *sf, void *uc) {
psiginfo(sf, "...:");
printf("%d\n", sf->si_code);
}
■ 이전의 설정 복원하기
□ sigaction(SIGTERM, NULL, &oact)
sigaction(SIGTERM, NULL, &oact) // 과거 설정 저장
act.sa_handler = SIG_IGN;
sigaction(SIGTERM, &act, NULL);
// do anything
sigaction(SIGTERM, &oact, NULL);
- SIGTERM 신호의 현재 설정을 oact에 저장
- SIG_IGN을 sa_handler에 설정하여 SIGTERM 신호를 무시하도록 지정함
- SIGTERM 신호를 무시하도록 설정을 변경함
- 처음 저장했던 oact를 사용해 SIGTERM 신호의 원래 설정을 복구함
- SIGTERM 신호는 이전 동작(예: 기본 동작 또는 사용자 정의 핸들러)으로 돌아감
■ alarm signal 설정
□ alarm()
#include <signal.h>
unsigned int alarm(unsigned int secs);
- 시간(초) 종료 후, SIGALARM을 보냄
- alarm은 exec 후에도 계속 작동, 그러나 fork 후에는 자식 process에 대한 alarm은 작동하지 않음
alarm(5);
alarm(10);
// 15초 기다리는 것이 아니라 10초로 대체됨
// 첫번째 알람에서 2초가 지났어도, 두번째 알람은 10초 후 울림
alarm(0) // 알람 끄기
- alarm은 누적되지 않음, 2번 사용되면 두번째 alarm으로 대체됨
- 두번째 alarm의 return 값이 첫 alarm의 잔여시간임
■ signal blocking
□ sigprocmask()
#include <signal.h>
int sigprocmask(int how, const sigset_t *set, sigset_t *oset)
- how: 신호 마스크를 어떻게 처리할지 지정하는 값
- SIG_SETMASK: 현재 신호 마스크를 set에 지정된 신호 집합으로 교체
- SIG_UNBLOCK: set에 있는 신호들을 현재 마스크에서 제거(차단 해제)
- SIG_BLOCK: set에 있는 신호들을 현재 마스크에 추가(차단)
- set: 변경할 신호 집합의 포인터.
- sigset_t 자료형으로, 차단하거나 차단 해제할 신호 집합을 지정
- oset: 함수 호출 전에 현재 신호 마스크를 저장할 포인터
- 이전 신호 마스크를 알고 싶다면 이 값을 사용
- 관심이 없다면 NULL로 지정
#include <signal.h>
#include <stdio.h>
int main() {
sigset_t set, oldset;
sigemptyset(&set); // 신호 집합 초기화
sigaddset(&set, SIGINT); // SIGINT(Ctrl+C) 신호 추가
// SIGINT 차단
if (sigprocmask(SIG_SETMASK, &set, &oldset) < 0) {
perror("sigprocmask");
}
printf("SIGINT is now blocked. Press Ctrl+C...\n");
sleep(5);
// 이전 신호 마스크로 복원
if (sigprocmask(SIG_SETMASK, &oldset, NULL) < 0) {
perror("sigprocmask");
}
printf("SIGINT is now unblocked.\n");
sleep(5);
return 0;
}
■ pause 시스템 호출
□ pause() : 호출된 프로세스의 실행을 무기한 대기 상태로 둠
#include <unistd.h>
int pause(void); // 항상 -1 반환
- signal 도착까지 실행을 일시 중단 ( CPU 사용 없이 )
- signal이 포착되면 처리 routine 수행하고 -1 return
'수업 정리 > UNIX 프로그래밍' 카테고리의 다른 글
[UNIX 프로그래밍] 11-2강 Shared memory (0) | 2024.12.07 |
---|---|
[UNIX 프로그래밍] 9강 - 메모리 매핑 (0) | 2024.11.17 |
[UNIX프로그래밍] 7강 - 프로세스 생성과 실행 (0) | 2024.10.19 |
[UNIX프로그래밍] 6강 - 프로세스 정보 (7) | 2024.10.16 |
[UNIX프로그래밍] 5강 - 시스템 정보 (1) | 2024.10.15 |