https://g.co/kgs/R7BWpf
Part 03 - 프로세스 간 통신
Chapter 08 - 시그널
07 - 알람 시그널
08 - 기타 시그널 처리 함수
일정 시간이 지난 후에 자동으로 시그널이 발생하게 하려면 알람 시그널(alarm signal)을 사용한다.
알람 시그널은 일정 시간 후에 한 번 발생시킬 수도 있고 일정한 간격을 두고 주기적으로 발생시킬 수도 있다.
#include <unistd.h>
unsigned int alarm(unsigned int seconds);
// seconds - 알람을 발생시킬 때까지 남은 시간(초 단위)
alarm() 함수가 인자로 지정한 시간이 지나면 SIGALRM 시그널이 생성되어 프로세서에 전달된다. 만약 시그널을 생성하기 전에 다시 alarm() 함수를 호출하면 이전 설정은 없어지고 재설정된다.
ex)
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
void sig_handler(int signo) {
psignal(signo, "Received Signal");
}
int main() {
signal(SIGALRM, sig_handler); // SIGALRM 시그널 처리를 위한 시그널 핸들러를 지정한다.
alarm(2); // alarm() 함수의 인자로 2초를 지정해 함수를 호출한다.
printf("Wait...\n");
sleep(3); // 3초 동안 sleep하고 있는 중에 2초가 지나면 SIGALRM 시그널이 발생해
// 시그널 핸들러가 호출된다.
}
// Wait...
// Received Signal: Alarm Clock
#include <sys/time.h>
int getitimer(int which, struct itimerval * curr_value);
getitimer() 함수는 타이머 정보를 검색하는 함수이다.
#include <sys/time.h>
int setitimer(int which, const struct itimerval *value, struct itimerval *ovalue);
setitimer()는 타이머를 설정하는 함수이다.
ex)
#include <sys/time.h>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
void sig_handler() {
printf("Timer Invoked..\n");
}
int main() {
struct itimerval it;
signal(SIGALRM, sig_handler); // SIGALRM 시그널 핸들러를 지정한다.
// 타이머의 간격을 2초로 설정하고 타이머에 현재 남은 시간을 3초로 설정한다.
// 즉, 최초의 시그널은 3초 후에 발생하고 이후 2초 간격으로 타이머가 동작하게 설정하는 것이다.
it.it_value.tv_sec = 3;
it.it_value.tv_usec = 0;
it.it_interval.tv_sec = 2;
it.it_interval.tv_usec = 0;
if (setitimer(ITIMER_REAL, &it, (struct itimerval *)NULL) == -1) {
perror("setitimer");
exit(1);
}
while (1) {
// 반복문으로 1초 동안 sleep했다가 getitimer() 함수를 호출해 남은 시간 정보를 출력하게 한다.
if (getitimer(ITIMER_REAL, &it) == -1) {
perror("getitimer");
exit(1);
}
printf("%d sec, %d msec.\n", (int)it.it_value.tv_sec,
(int)it.it_value.tv_usec);
sleep(1);
}
}
// 처음 남은 시간이 3초였으므로 while문을 세번 반복한 후에 타이머가 만료되어
// SIGALRM 시그널을 생성하고 이후에는 2초 간격으로 타이머가 작동함을 알 수 있다.
// 무한반복문이므로 강제종료 해야한다.
리눅스에서는 시그널 정보를 출력하거나, 시그널이 올 때까지 기다리거나, 시그널을 보내는 등의 시그널 처리를 위한 기타 함수를 제공한다.
#include <signal.h>
void psignal(int sig, const char *s);
psignal() 함수는 두 번째 인자인 s로 지정한 문자열을 출력한 수 첫 번째 인자인 sig로 지정한 시그널을 가리키는 이름을 붙여 표준 오류로 출력한다.
#include <string.h>
char *strsignal(int sig);
strsignal() 함수는 인자로 받은 시그널을 가리키는 이름을 문자열로 리턴한다. 인자로 받은 시그널이 없으면 NULL을 리턴한다.
#include <signal.h>
int sighold(int sig);
int sigrelse(int sig);
sighold() 함수는 인자로 받은 시그널을 프로세스의 시그널 마스크에 추가한다. 시그널 마스크에 추가된 시그널은 블로킹되어 해당 시그널을 받지 않는다.
ex)
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
void sig_handler(int signo) {
char *s;
s = strsignal(signo);
printf("Received Signal : %s\n", s);
}
int main() {
if (signal(SIGINT, sig_handler) == SIG_ERR) {
perror("signal");
exit(1);
}
sighold(SIGINT); // sighold() 함수를 사용해 SIGINT 시그널을 블로킹한다. Ctrl + /로 강제 종료한다.
pause();
}
#include <signal.h>
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
sigprocmask() 함수는 set에 지정한 시그널 집합을 블로킹할 것인지 해제할 것인지를 how에 지정해 호출한다. 첫 번째 인자인 how에 올 수 있는 값은 다음과 같다.
두 번째 인자인 set은 블로킹하거나 해제할 시그널 집합을 가리키고, 세 번째 인자인 oldset에는 NULL 아니면 이전 설정값이 저장된다.
ex)
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
int main() {
sigset_t new;
sigemptyset(&new); // 시그널 집합에 SIGINT와 SIGQUIT 시그널을 설정한다.
sigaddset(&new, SIGINT);
sigaddset(&new, SIGQUIT);
sigprocmask(SIG_BLOCK, &new, (sigset_t *)NULL);
// sigprocmask() 함수를 사용해 SIGINT 시그널과 SIGQUIT 시그널을 블로킹한다.
printf("Blocking Signals : SIGINT, SIGQUIT\n");
printf("Send SIGQUIT\n");
kill(getpid(), SIGQUIT); // SIGQUIT 시그널을 보낸다.
printf("UnBlocking Signals\n");
sigprocmask(SIG_UNBLOCK, &new, (sigset_t *)NULL);
// 블로킹된 SIGQUIT 시그널을 해제한다.
}
#include <unistd.h>
int pause(void);
pause() 함수는 프로세스가 종료하거나 시그널 잡기 함수를 호출하는 시그널을 받을 때까지 프로세스를 대기시킨다. pause() 함수는 시그널 잡기 함수로, 시그널을 잡았을 때만 -1을 리턴한다.
#include <signal.h>
int sigpause(int sigmask);
int sigpause(int sig);
sigpause() 함수는 인자로 지정한 시그널을 프로세스의 시그널 마스크에서 제거하고 프로세스가 시그널을 받을 때까지 기다린다.
#include <signal.h>
itn sigsuspend(const sigset_t *mask);
sigsuspend() 함수는 인자로 지정한 시그널 집합에 설정된 시그널들로 프로세스의 시그널 마스크를 교체하고, 블로킹되지 않은 시그널이 도착할 때까지 프로세스의 수행을 멈추고 기다린다.
ex)
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
void sig_handler(int signo) {
psignal(signo, "Received Signal:");
}
int main() {
sigset_t set;
signal(SIGALRM, sig_handler); // 알람 시그널을 받으면 시그널 핸들러를 호출하도록 설정한다.
sigfillset(&set); // 시그널 마스크에서 모든 시그널을 블로킹한 후 SIGALRM만 해제한다.
sigdelset(&set, SIGALRM);
alarm(3); // 3초 후에 알람 시그널이 발생하도록 설정한다.
printf("Wait...\n");
sigsuspend(&set); // sigsuspend() 함수를 사용해 시그널이 도착하기를 기다린다.
}
#include <signal.h>
int sigsend(idtype, id_t id, int sig);
sigsend() 함수는 sig로 지정한 시그널을 id에 지정한 프로세스나 프로세스 그룹에 보낸다.
#include <signal.h>
int sigignore(int sig);
sigignore() 함수는 인자로 지정한 시그널의 처리 방법을 SIG_IGN으로 설정함으로써 시그널을 무시하도록 한다.