#include <stdio.h>
#include <signal.h>
#include <string.h>
#define INPUTLEN 100
void inthandler(int s) {
printf("Received siganl %d .. waiting\n", s);
sleep(2);
printf("Leaving inthandler\n");
}
void quithandler(int s) {
printf("Received siganl %d .. waiting\n", s);
sleep(3);
printf("Leaving quithandler\n");
}
int main(int ac, char *av[]) {
void inthandler(int);
void quithandler(int);
char input[INPUTLEN];
int nchars;
signal(SIGINT, inthandler);
signal(SIGQUIT, quithandler);
do {
printf("\nType a message\n");
nchars = read(0, input, (INPUTLEN-1)); //read(fd, buf, size);
if (nchars == -1)
perror("read returned an error");
else {
input[nchars] = '\0'; // 맨 마지막에 널문자
printf("You typed: %s", input);
}
}
while (strncmp(input, "quit", 4) != 0);
}
inthandler: 이 함수는 SIGINT 시그널을 처리하기 위해 등록되어 있습니다. 일반적으로 사용자가 터미널에서 Ctrl+C를 누를 때 생성됩니다.
quithandler: 이 함수는 SIGQUIT 시그널을 처리하기 위해 등록되어 있습니다. 일반적으로 사용자가 터미널에서 Ctrl+\를 누를 때 생성됩니다.

SIGINT와 SIGQUIT은 모두 사용자에 의해 터미널에서 발생시키는 시그널이지만 몇 가지 중요한 차이가 있습니다.
원래 목적:
SIGINT (Interrupt)은 사용자가 프로그램에게 정상적으로 종료하라고 요청하는 시그널입니다. 주로 Ctrl+C를 사용하여 프로세스를 중지하는 데 사용됩니다.SIGQUIT (Quit)은 사용자가 프로그램에게 종료하라는 요청을 보내지만, SIGINT와 달리 해당 프로세스가 코어 덤프를 생성하도록 요청합니다. 주로 Ctrl+\를 사용하여 프로세스를 중지하는 데 사용됩니다.동작:
SIGINT를 받은 프로세스는 종료되며, 종료 전에 시그널 핸들러를 실행할 수 있습니다. 일반적으로는 정상적인 종료를 수행하도록 프로그램이 설계되어 있습니다.SIGQUIT을 받은 프로세스는 종료되고, 종료 전에 SIGQUIT 핸들러를 실행하고 코어 덤프를 생성합니다. 이는 프로그램이 비정상 종료되었거나 디버깅이 필요한 경우 유용합니다.코어 덤프 생성:
SIGINT는 기본적으로 코어 덤프를 생성하지 않습니다. 프로그램을 종료하면 종료 상태만 반환됩니다.SIGQUIT은 종료 전에 코어 덤프를 생성하도록 요청합니다. 이는 프로그램이 종료되기 전에 메모리 상태 및 실행 상태를 파일로 저장하여 디버깅에 사용할 수 있도록 합니다.키 조합:
SIGINT는 Ctrl+C를 눌러서 발생시킵니다.SIGQUIT는 Ctrl+\를 눌러서 발생시킵니다.일반적으로 SIGINT는 프로그램이 정상적으로 종료될 때 사용되고, SIGQUIT은 디버깅이나 예상치 못한 문제 해결을 위해 코어 덤프를 생성할 때 사용됩니다.
네, 맞습니다. newhandler.sa_flags = SA_RESETHAND | SA_RESTART; 코드 라인은 두 가지 플래그를 설정하고 있습니다.
SA_RESETHAND:
SA_RESTART:
fgets 등)가 실행 중에 SIGINT 시그널이 발생하면, 해당 함수는 중단된 지점에서 다시 시작됩니다.결과적으로, 한 번 SIGINT 시그널이 발생하고 해당 핸들러 함수가 실행되면, 그 이후에는 SIGINT 시그널이 발생해도 핸들러 함수가 다시 호출되지 않습니다. 대신에 디폴트 핸들러로 재설정되며, 입출력 함수는 중단된 지점에서 재시작됩니다. 이 동작은 SA_RESETHAND와 SA_RESTART 플래그의 조합으로 결정됩니다.
fgets 함수가 호출되어 사용자로부터 입력을 받을 때, "1234"를 입력하였습니다.SIGINT 시그널이 발생하여 시그널 핸들러 함수 inthandler가 호출되었습니다.inthandler 함수에서 "Called with signal 2"를 출력하고, sleep(2)에 의해 2초 동안 대기한 후 "done handling signal 2"를 출력하였습니다.fgets 함수가 중단된 지점에서 다시 시작되어 사용자로부터 입력을 받을 때, "5678"을 입력하였습니다.따라서 "1234"는 출력되지 않는 것이 정상입니다. 왜냐하면 시그널 핸들러 함수 inthandler에서 sleep(2)에 의해 2초 동안 대기하는 동안, fgets 함수는 중단된 상태이며, 그 동안에는 입력이 받아지지 않습니다. 즉, "1234"는 시그널 핸들러 함수가 처리되는 동안 입력되었지만, 그 이후에야 다시 fgets 함수가 실행되어 "5678"이 입력되고 출력되었습니다.
#include <stdio.h>
#include <signal.h>
int main() {
int i=5;
sigset_t sigs; // 시그널을 포함하는 시그널 집합
sigset_t prevsigs; // 현재 시그널 마스크를 저장하기 위한 이전 시그널 집합
sigemptyset(&sigs);
sigaddset(&sigs, SIGINT);
printf("Critical section in\n");
// sigprocmask(): sigs 시그널 집합에 포함된 시그널을 블록함.
// 현재 시그널 마스크는 prevsigs에 저장됩니다.
sigprocmask(SIG_BLOCK, &sigs, &prevsigs);
// SIGINT 시그널이 블록되어 있음
while (i--) {
sleep(1);
}
sigprocmask(SIG_SETMASK, &prevsigs, NULL);
// 이전 시그널 마스크로 복구하여 SIGIN 블록을 해제
printf("Critical section out\n");
whlie (i--) {
sleep(1);
}
wait 함수와 waitpid 함수의 차이점
pid_t wait(int *status);
wait 함수는 모든 자식 프로세스 중 하나의 종료를 기다립니다.
대기 중인 모든 자식 프로세스 중 하나가 종료되면 해당 자식 프로세스의 프로세스 ID를 반환합니다.
부모 프로세스는 자식 프로세스의 종료 상태를 status에 저장합니다.
대기 중인 자식 프로세스가 없다면, 즉시 반환합니다.
pid_t waitpid(pid_t pid, int *status, int options);
waitpid 함수는 특정 자식 프로세스의 종료를 기다립니다.
pid 인자를 사용하여 대기할 자식 프로세스의 PID를 지정할 수 있습니다.
options 인자를 사용하여 대기 방식을 세부적으로 제어할 수 있습니다.
pid > 0이면 해당 PID의 자식 프로세스가 종료될 때까지 대기합니다.
pid == -1이면 모든 자식 프로세스 중 하나가 종료될 때까지 대기합니다.
pid == 0이면 현재 프로세스 그룹 내의 모든 자식 프로세스 중 하나가 종료될 때까지 대기합니다.
pid < -1이면 프로세스 그룹 ID가 -pid와 같은 모든 자식 프로세스 중 하나가 종료될 때까지 대기합니다.
반환 값은 종료된 자식 프로세스의 PID입니다.
주요 옵션:
WNOHANG (0x01): 대기 중인 자식이 종료되지 않았다면 즉시 반환합니다. 대기 중인 자식이 없으면 0을 반환합니다.
WUNTRACED (0x02): 대기 중인 자식이 정지된 상태인 경우에도 반환합니다.
WCONTINUED (0x04): 대기 중인 자식이 재개된 경우에도 반환합니다.
wait 함수는 간단하게 모든 자식 프로세스 중 하나의 종료를 기다립니다.
waitpid 함수는 더 세부적인 제어가 가능하며, 특정 PID의 자식을 대기하거나 다양한 옵션을 사용할 수 있습니다.