UNIX 환경 고급 프로 그래 밍 - 신호 기본 개요 와 signal 함수

6102 단어
1. 신 호 를 이해 하기 위해 먼저 우리 가 가장 잘 아 는 장면 부터 말 합 니 다. 1. 사용자 가 명령 을 입력 하고 Shell 에서 프론트 프로 세 스 를 시작 합 니 다.2. 사용자 가 Ctrl - C 를 누 르 면 이 키보드 입력 은 하드웨어 인 터 럽 트 가 발생 합 니 다.3. CPU 가 현재 이 프로 세 스 의 코드 를 실행 하고 있다 면 이 프로 세 스 의 사용자 공간 코드 는 실행 을 중단 하고 CPU 는 사용자 상태 에서 커 널 처리 하드웨어 로 전환 합 니 다.4. 터미널 드라이버 는 Ctrl - C 를 SIGINT 신호 로 해석 하여 이 프로 세 스 의 PCB 에 기록 합 니 다 (SIGINT 신 호 를 이 프로 세 스에 보 냈 다 고 할 수 있 습 니 다).
5. 커 널 에서 이 프로 세 스 로 돌아 가 는 사용자 공간 코드 가 계속 실행 되 기 전에 먼저 PCB 에 기 록 된 신 호 를 처리 하고 SIGINT 신호 가 처리 되 어야 하 는 것 을 발견 합 니 다. 이 신호 의 기본 처리 동작 은 프로 세 스 를 종료 하 는 것 이기 때문에 사용자 공간 코드 로 돌아 가지 않 고 프로 세 스 를 직접 종료 합 니 다.
kill - l 명령 으로 시스템 이 정의 하 는 신호 목록 을 볼 수 있 습 니 다. 모든 신 호 는 하나의 번호 와 하나의 매크로 정의 이름 이 있 습 니 다. 이 매크로 정 의 는 signal. h 에서 찾 을 수 있 습 니 다. 예 를 들 어 정의 가 있 습 니 다.\# define SIGINT 2.번호 34 이상 은 실시 간 신호 입 니 다. 이 신 호 는 각각 어떤 조건 에서 발생 합 니까? 기본 적 인 처리 동작 은 무엇 입 니까?
[1,31]       신뢰 할 수 없 는 신호, 여러 신 호 는 줄 을 서지 않 고 한 개 만 유지 합 니 다. 즉, 신 호 를 잃 어 버 릴 수 있 습 니 다.
[34,64]    신뢰 할 수 있 습 니 다 (실시 간 신호). 대기 신 호 를 잃 어 버 리 지 않 고 sigquue 로 신 호 를 보 낼 수 있 습 니 다. 0 ~ 31 에 부족 한 정의 가 있 는 것 같 지 않 습 니 다.
2. 신호 가 발생 하 는 조건 은 주로 다음 과 같다.
1. 사용자 가 터미널 에서 일부 키 를 누 를 때 터미널 드라이버 는 프론트 프로 세 스에 신 호 를 보 냅 니 다. 예 를 들 어 Ctrl - C 는 SIGINT 신 호 를 보 내 고 Ctrl -\는 SIGQUIT 신 호 를 보 내 며 Ctrl - Z 는 SIGSTP 신 호 를 보 냅 니 다.
2. 하드웨어 이상 신호 가 발생 합 니 다. 이러한 조건 은 하드웨어 에서 커 널 을 감지 하고 알려 준 다음 에 커 널 은 현재 프로 세 스에 적당 한 신 호 를 보 냅 니 다.예 를 들 어 현재 프로 세 스 가 0 으로 나 누 는 명령 을 실행 하면 CPU 의 연산 단위 에 이상 이 생 길 수 있 습 니 다. 커 널 은 이 이상 을 SIGFPE 신호 로 프로 세 스에 보 냅 니 다.
3. 현재 프로 세 스 가 불법 메모리 주 소 를 방문 하면 MMU 에 이상 이 생 길 수 있 습 니 다. 커 널 은 이 이상 을 SIGSEGV 신호 로 프로 세 스에 보 냅 니 다.
4. 하나의 프로 세 스 가 kill (2) 함 수 를 호출 하면 다른 프로 세 스에 신 호 를 보 낼 수 있 습 니 다.
5. kill (1) 명령 으로 특정한 프로 세 스에 신 호 를 보 낼 수 있 습 니 다. kill (1) 명령 도 kill (2) 함 수 를 호출 하여 이 루어 집 니 다. 신 호 를 명확 하 게 지정 하지 않 으 면 SIGTERM 신 호 를 보 냅 니 다. 이 신호 의 기본 처리 동작 은 프로 세 스 를 종료 하 는 것 입 니 다.
6. raise: 자신 에 게 신 호 를 보낸다.raise (sig) 는 kill (getpid (), sig) 와 같 습 니 다.7. killpg: 프로 세 스 그룹 에 신 호 를 보 냅 니 다.killpg (pgrp, sig) 는 kill (- pgrp, sig) 와 같 습 니 다.8. sigquue: 프로 세 스에 신 호 를 보 내 고 줄 을 서 는 것 을 지원 하 며 정 보 를 추가 할 수 있 습 니 다.
9. 커 널 에서 특정한 소프트웨어 조건 이 발생 하 는 것 을 감지 하면 신호 로 프로 세 스 를 알 릴 수 있 습 니 다. 예 를 들 어 알 람 이 시간 을 초과 하면 SIGALRM 신호 가 발생 하고 읽 기 단 이 닫 힌 파이프 에 데 이 터 를 쓸 때 SIGIPE 신호 가 발생 합 니 다.
3. 사용자 프로그램 은 signal (2)/sigaction (2) 함 수 를 호출 하여 커 널 에 특정한 신 호 를 어떻게 처리 하 는 지 알려 줄 수 있 습 니 다 (등록 하지 않 으 면 결 성 된 처리). 선택 할 수 있 는 처리 동작 은 세 가지 가 있 습 니 다. 1. 이 신 호 를 무시 합 니 다 (SIG IGN).두 가지 신 호 를 무시 할 수 없습니다: SIGKILL 과 SIGSTOP.2. 이 신호 의 기본 처리 동작 (SIG DFL) 을 실행 합 니 다.3. 신호 처리 함 수 를 제공 하고 커 널 이 이 신 호 를 처리 할 때 사용자 상태 로 전환 하여 이 처리 함 수 를 실행 하도록 요구 합 니 다. 이런 방식 을 캡 처 (catch) 신호 라 고 합 니 다.
4. 신호 와 중단 의 차이
신호 와 인 터 럽 트 의 유사 점: (1) 같은 비동기 통신 방식 을 사용 했다.(2) 신호 가 감지 되 거나 요청 을 중단 할 때 실행 중인 프로그램 을 중단 하고 해당 하 는 처리 프로그램 을 실행 합 니 다.(3) 모두 처리 가 끝 난 후에 원래 의 정지점 으로 돌아간다.(4) 신호 나 중단 을 모두 차단 할 수 있다.신호 와 중단 의 차이: (1) 중단 은 우선 순위 가 있 고 신 호 는 우선 순위 가 없 으 며 모든 신 호 는 평등 하 다.(2) 신호 처리 프로그램 은 사용자 상태 에서 실행 되 고 중단 처리 프로그램 은 핵심 상태 에서 실 행 됩 니 다.(3) 응답 을 중단 하 는 것 은 신속 한 것 이 고 신호 응답 은 보통 비교적 큰 시간 지연 이 있다.
5. signal (2) 신호 등록 함수
typedef void (*__sighandler_t) (int);#define SIG_ERR ((__sighandler_t) -1)#define SIG_DFL ((__sighandler_t) 0)#define SIG_IGN ((__sighandler_t) 1)
함수 원형:sighandler_t signal(int signum, __sighandler_t handler);매개 변수 signal 은 signum 과 handler 두 개의 매개 변 수 를 가 진 함수 입 니 다. 캡 처 하거나 차단 하려 는 신 호 는 매개 변수 signum 에 의 해 제 시 됩 니 다. 지정 한 신 호 를 받 을 때 호출 할 함 수 는 handler 에 의 해 제 시 됩 니 다. handler 라 는 함 수 는 int 형식의 매개 변수 (즉 받 은 신호 코드) 가 있어 야 합 니 다. 그 자체 의 유형 은 voidhandler 일 수도 있 고 두 개의 특수 값 일 수도 있 습 니 다. SIGIGN 이 신 호 를 차단 합 니 다.SIG_DFL    기본 행동 을 복원 합 니 다.
반환 값: 이전 신호 처리 함수 포인터 (handler 가 아 닌 것 을 주의 하 십시오) 를 되 돌려 줍 니 다. 오류 가 있 으 면 SIG ERR (- 1) 을 되 돌려 줍 니 다.
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<fcntl.h>
#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<string.h>
#include<signal.h>

#define ERR_EXIT(m) \
    do { \
        perror(m); \
        exit(EXIT_FAILURE); \
    } while(0)

void handler(int sig);

int main(int argc, char *argv[])
{
    __sighandler_t oldhandler;
    oldhandler = signal(SIGINT, handler); //                  
//    if (oldhandler == SIG_ERR)
//        ERR_EXIT("signal error");
      if (oldhandler == SIG_DFL)  //  oldhandler    SIG_DFL

	      printf("huang
"); while (getchar() != '
') ; /* signal(SIGINT, SIG_DFL) */ // if (signal(SIGINT, oldhandler) == SIG_ERR) // ERR_EXIT("signal error"); if (signal(SIGINT, oldhandler) == handler) // :signal(SIGINT, oldhandler) handler printf("cheng
"); for (; ;) ; return 0; } void handler(int sig) { printf("recv a sig=%d
", sig); }

테스트 출력 은 다음 과 같 습 니 다:
huangcheng@ubuntu:~$ ./a.out
huang
^Crecv a sig=2
^Crecv a sig=2

cheng
^C

    프로그램 실행 이 시작 되 었 습 니 다. SIGINT 신호 처리 함수 가 등록 되 었 기 때문에 우 리 는 ctrl + c 를 누 르 면 여느 때 처럼 프로그램 을 종료 하지 않 고 recv a 만 인쇄 했 습 니 다. sig = 2. 이어서 리 턴 을 누 르 고 SIGINT 의 기본 처 리 를 재 등 록 했 습 니 다. 이때 ctrl + c 프로그램 이 종 료 됩 니 다.
프로그램의 29 ~ 38 줄 을 다음 과 같이 바 꿉 니 다.
for (; ;)
{
    pause(); //              (           )
    //   schedule()           ,
    //               cpu
    printf("pause return
"); }

     pause 함수 호출: 프로 세 스 를 수면 을 중단 할 수 있 는 상태 로 설정 합 니 다. 그리고 schedule () 를 호출 하여 Liux 프로 세 스 스케줄 러 가 다른 프로 세 스 를 찾 아 실행 하도록 합 니 다. pause 는 호출 자 프로 세 스 를 걸 어 놓 고 신호 가 캡 처 처 처 될 때 까지 함수 가 돌아 갑 니 다.
pause 를 호출 하 는 장점 은 신 호 를 기다 리 는 동안 cpu 를 내 보 내 고 시스템 이 다른 프로 세 스 를 실행 하도록 하 는 것 입 니 다. 완전한 순환 이 아 닙 니 다. 물론 이렇게 ctrl + c 는 프로그램 을 종료 할 수 없습니다. 우 리 는 ctrl +\를 사용 하여 SIGQUIT 신호 종료 프로그램 을 만 들 수 있 습 니 다.
     사실 man 매 뉴 얼 에 따 르 면 signal 함 수 는 이식 성 이 좋 지 않 습 니 다. SIG DFL, SIG IGN 에 만 사용 하 는 것 이 좋 습 니 다. 신호 처리 함 수 를 sigaction 으로 등록 하 는 것 이 좋 습 니 다.
메모: 프로 세 스 가 fork 를 호출 할 때 하위 프로 세 스 는 부모 프로 세 스 의 신호 처리 방식 을 계승 합 니 다.

좋은 웹페이지 즐겨찾기