>  기사  >  시스템 튜토리얼  >  Linux에서의 신호 메커니즘: 프로세스 간 통신 및 제어를 위해 신호를 사용하는 방법

Linux에서의 신호 메커니즘: 프로세스 간 통신 및 제어를 위해 신호를 사용하는 방법

WBOY
WBOY앞으로
2024-02-12 12:40:031173검색

Linux 下的信号机制:如何使用信号进行进程间通信和控制

Signal은 Linux 시스템에서 일반적으로 사용되는 프로세스 간 통신 및 제어 방법으로, 한 프로세스에서 다른 프로세스에 간단한 메시지를 보내 특정 이벤트나 상태가 발생했음을 알릴 수 있습니다. 신호의 기능은 비정상적이거나 긴급한 상황에 대처하기 위해 시스템의 응답성과 유연성을 향상시키는 것입니다. Linux 시스템에는 SIGINT, SIGTERM, SIGKILL 등과 같은 다양한 종류의 신호가 있습니다. 각 신호는 고유한 의미와 기능을 가지며 다양한 시나리오와 요구 사항에 적합합니다. 그러나 Linux의 신호 메커니즘을 정말로 이해하고 있습니까? Linux에서 프로세스 간 통신 및 제어를 위해 신호를 사용하는 방법을 알고 있습니까? Linux에서 신호를 처리하고 무시하는 방법을 알고 계십니까? 이 기사에서는 Linux에서 신호 메커니즘에 대한 관련 지식을 자세히 소개하여 Linux에서 이 강력한 프로세스 간 통신 및 제어 방법을 더 잘 사용하고 이해할 수 있도록 합니다.

1. 신호의 기본 개념

이 섹션에서는 먼저 신호의 몇 가지 기본 개념을 소개한 다음 몇 가지 기본 신호 유형 및 신호에 해당하는 이벤트를 제공합니다. 기본 개념은 신호를 이해하고 사용하며 신호 메커니즘을 이해하는 데 특히 중요합니다. 신호가 무엇인지 살펴보겠습니다.

1. 기본 개념

소프트 인터럽트 신호(신호, 신호라고도 함)는 비동기 이벤트가 발생했음을 프로세스에 알리는 데 사용됩니다. 프로세스는 시스템 호출 종료를 통해 서로 소프트 인터럽트 신호를 보낼 수 있습니다. 커널은 내부 이벤트로 인해 프로세스에 신호를 보내 이벤트가 발생했음을 프로세스에 알릴 수도 있습니다. 신호는 발생한 이벤트를 프로세스에 알리는 데에만 사용되며 프로세스에 데이터를 전달하지 않습니다.

신호를 수신하는 프로세스는 다양한 신호에 대해 서로 다른 처리 방법을 가지고 있습니다. 처리 방법은 세 가지 범주로 나눌 수 있습니다. 첫 번째는 처리해야 하는 신호의 경우 프로세스에서 이를 처리하는 처리 기능을 지정할 수 있습니다. 두 번째 방법은 신호를 무시하고 마치 아무 일도 일어나지 않은 것처럼 신호에 대해 아무 작업도 수행하지 않는 것입니다. 세 번째 방법은 신호 처리를 위한 시스템의 기본값을 유지하는 것입니다. 이 기본 작업은 대부분의 신호에 대한 기본 작업이 프로세스를 종료하는 것입니다. 프로세스는 시스템 호출 신호를 사용하여 특정 신호에 대한 프로세스의 처리 동작을 지정합니다.

프로세스 테이블 항목에는 소프트 인터럽트 신호 필드가 있습니다. 이 필드의 각 비트는 신호에 해당합니다. 신호가 프로세스에 전송되면 해당 비트가 설정됩니다. 이를 통해 프로세스가 동시에 다른 신호를 유지할 수 있지만 동일한 신호에 대해 프로세스는 처리 전에 얼마나 많은 신호가 왔는지 알 수 없다는 것을 알 수 있습니다.

2. 신호 유형

신호를 보내는 이유는 다양합니다. 다음은 다양한 신호를 이해하기 위해 신호를 보내는 이유에 따른 간단한 분류입니다.

(1) 프로세스 종료와 관련된 신호. 이러한 유형의 신호는 프로세스가 종료되거나 하위 프로세스가 종료될 때 발생합니다.

(2) 프로세스 예외 이벤트와 관련된 신호입니다. 예를 들어 프로세스가 경계를 넘거나, 읽기 전용 메모리 영역(예: 프로그램 텍스트 영역)에 쓰려고 시도하거나, 권한 있는 명령을 실행하거나 기타 다양한 하드웨어 오류가 발생합니다.
(3) 시스템 호출 중 복구할 수 없는 조건 발생과 관련된 신호입니다. 예를 들어 시스템 호출 exec를 실행하면 원래 리소스가 해제되고 현재 시스템 리소스가 소진됩니다.
(4) 시스템 호출을 실행하는 동안 예측할 수 없는 오류 조건과 관련된 신호입니다. 존재하지 않는 시스템 호출을 실행하는 등.
(5) 사용자 모드의 프로세스가 보내는 신호. 예를 들어, 프로세스는 다른 프로세스에 신호를 보내기 위해 시스템 호출 kill을 호출합니다.
(6) 단말기 상호작용과 관련된 신호. 예를 들어, 사용자가 터미널을 닫거나 Break 키를 누릅니다.
(7) 프로세스 실행 신호를 추적합니다.

Linux에서 지원하는 시그널 목록은 다음과 같습니다. 많은 신호가 기계의 아키텍처와 관련되어 있습니다. 나열된 첫 번째 신호는 POSIX.1에 나열된 신호입니다.

신호 값 처리 동작 신호를 보내는 이유

———————————————————————-
으아악

다음 신호는 POSIX.1에는 나열되지 않지만 SUSv2에는 나열되어 있습니다

신호값 처리 동작 신호를 보내는 이유

——————————————————————–
으아악

다른 신호는 다음과 같습니다

신호값 처리 동작 신호를 보내는 이유

———————————————————————-
으아악

(여기서 -는 신호가 구현되지 않았다는 의미입니다. 의미가 부여된 값은 3개이며 첫 번째 값은 일반적으로 Alpha 및 Sparc에서 유효하며 중간 값은 i386 및 ppc 및 sh에 해당하고 마지막 값은 값은 Alpha의 신호 29 SIGINFO/SIGPWR, Sparc의 SIGLOST에 해당합니다.)

처리 조치 항목의 글자 의미는 다음과 같습니다
A 기본 동작은 프로세스를 종료하는 것입니다
B 기본 동작은 이 신호를 무시하는 것입니다
C의 기본 동작은 프로세스를 종료하고 커널 이미지 덤프(코어 덤프)를 수행하는 것입니다
D 기본 동작은 프로세스를 중지하는 것입니다
E 신호를 캡처할 수 없습니다
F 신호는 무시할 수 없습니다

위에 소개된 신호는 일반 시스템에서 지원됩니다. 기본적으로 다양한 신호의 이름, 기능 및 처리 동작이 표 형식으로 소개됩니다. 다양한 기본 처리 작업의 의미는 다음과 같습니다. 프로그램 종료는 프로세스가 종료됨을 의미합니다. 신호를 무시한다는 것은 신호를 처리하지 않고 신호를 삭제하는 것을 의미합니다. 디버깅(예: ptrace 시스템 호출), 커널 이미지 덤프는 메모리에 있는 프로세스 데이터의 이미지와 프로세스의 커널 구조에 저장된 내용의 일부를 특정 형식으로 파일 시스템에 덤프하는 것을 의미하며 프로세스는 실행을 종료합니다. 이런 방식으로 프로그래머는 프로세스가 실행될 때 데이터 값을 편리하게 얻을 수 있어 덤프 원인을 파악하고 프로그램을 디버그할 수 있다는 이점이 있습니다.

SIGKILL 및 SIGSTOP 신호는 포착되거나 무시될 수 없습니다. SIGIOT 및 SIGABRT 신호는 하나의 신호입니다. 동일한 신호라도 시스템에 따라 다른 값을 가질 수 있음을 알 수 있으므로 신호의 값을 직접 사용하기보다는 신호에 정의된 이름을 사용하는 것이 좋습니다.

2. 신호 메커니즘

신호의 기본 개념은 이전 섹션에서 소개되었습니다. 이번 섹션에서는 커널이 신호 메커니즘을 구현하는 방법을 소개합니다. 즉, 커널이 프로세스에 신호를 보내는 방법, 프로세스가 신호를 받는 방법, 프로세스가 신호에 대한 응답을 제어하는 ​​방법, 커널이 프로세스에서 수신한 신호를 언제 어떻게 처리하는지에 대한 것입니다. 또한 신호에서 setjmp와 longjmp가 수행하는 역할을 소개하고 싶습니다.

1. 커널의 기본 신호 처리 방법

커널이 프로세스에 소프트 인터럽트 신호를 보내는 방법은 프로세스가 위치한 프로세스 테이블 항목의 신호 필드에 신호에 해당하는 비트를 설정하는 것입니다. 여기에 추가해야 할 점은 신호가 절전 모드로 들어가는 프로세스의 우선 순위에 따라 결정된다는 점입니다. 프로세스가 중단될 수 있는 우선 순위에서 절전 모드로 전환되면 그렇지 않으면 프로세스를 깨우기만 하면 됩니다. 프로세스를 깨우지 않고 해당 비트에 해당하는 프로세스 테이블의 신호. 이는 프로세스가 신호 수신 여부를 확인하는 시간이 프로세스가 커널 모드에서 사용자 모드로 돌아가려고 할 때이거나 프로세스가 적절하게 낮은 우선순위의 절전 상태에 들어가거나 나가려고 할 때이기 때문에 중요합니다.

프로세스가 수신한 신호를 커널이 처리하는 타이밍은 프로세스가 커널 모드에서 사용자 모드로 돌아올 때입니다. 따라서 프로세스가 커널 모드에서 실행 중인 경우 소프트 인터럽트 신호는 즉시 적용되지 않으며 사용자 모드로 돌아올 때까지 기다려야 합니다. 프로세스는 신호를 처리한 후에만 사용자 모드로 돌아갑니다. 프로세스에는 사용자 모드에서 처리되지 않은 신호가 없습니다.

커널은 프로세스의 컨텍스트에서 프로세스가 수신한 소프트 인터럽트 신호를 처리하므로 프로세스는 실행 상태에 있어야 합니다. 앞서 개념을 소개할 때 언급했듯이 신호 처리에는 세 가지 유형이 있습니다. 프로세스는 신호를 받은 후 종료됩니다. 프로세스는 신호를 받은 후 사용자가 설정한 기능을 실행하여 신호를 호출합니다. 시스템. 프로세스가 무시하는 신호를 받으면 프로세스는 신호를 버리고 신호가 수신되지 않은 것처럼 계속됩니다. 프로세스가 캡처할 신호를 수신하면 프로세스가 커널 모드에서 사용자 모드로 돌아올 때 사용자 정의 함수가 실행됩니다. 더욱이, 사용자 정의 함수를 실행하는 방법은 매우 영리합니다. 커널은 사용자 스택에 새 레이어를 생성하고, 이 레이어에서 반환 주소의 값은 사용자 정의 처리 함수의 주소로 설정됩니다. 프로세스가 커널에서 복귀하여 스택의 상단을 팝하면 사용자 정의 함수로 돌아가고, 함수에서 복귀한 후 스택의 상단을 팝하면 원래 커널에 진입했던 위치로 돌아갑니다. . 그 이유는 사용자 정의 처리 함수가 커널 모드에서 실행될 수 없고 실행이 허용되지 않기 때문입니다(사용자 정의 함수가 커널 모드에서 실행되면 사용자는 모든 권한을 얻을 수 있습니다).

신호 처리 방법에는 특히 주의해야 할 몇 가지 사항이 있습니다. 먼저, 일부 시스템에서는 프로세스가 인터럽트 신호를 처리하고 사용자 모드로 복귀할 때 커널은 사용자 영역에 설정된 신호 처리 루틴의 주소를 클리어한다. 즉, 다음번에 프로세스가 신호 처리 방식을 변경할 때, 다음 신호가 도착하기 전에 신호 시스템 호출이 다시 사용되지 않는 한 기본값입니다. 이로 인해 프로세스가 signal을 호출하기 전에 신호를 받아 종료될 수 있습니다. BSD에서는 커널이 더 이상 이 주소를 지우지 않습니다. 하지만 이 주소를 지우지 않으면 프로세스가 너무 빨리 신호를 받게 되어 스택 오버플로가 발생할 수 있습니다. 위와 같은 상황을 피하기 위해서입니다. BSD 시스템에서 커널은 하드웨어 인터럽트 처리 방법을 시뮬레이션합니다. 즉, 인터럽트를 처리할 때 이러한 유형의 새로운 인터럽트 수신을 방지합니다.

두 번째로 주목해야 할 점은 프로세스가 시스템 호출 중일 때 캡처할 신호가 발생하고 프로세스가 인터럽트 가능한 우선 순위 수준에서 절전 모드로 전환되면 신호로 인해 프로세스가 longjmp를 수행하고 절전 모드에서 벗어나게 된다는 것입니다. 상태에서 사용자 모드로 돌아가 신호 처리 루틴을 실행합니다. 신호 처리 루틴에서 복귀할 때 프로세스는 시스템 호출에서 복귀한 것처럼 동작하지만 시스템 호출이 중단되었음을 나타내는 오류 코드를 반환합니다. BSD 시스템에서는 커널이 시스템 호출을 자동으로 다시 시작할 수 있다는 점에 유의해야 합니다.

세 번째로 주의할 점: 프로세스가 인터럽트 가능한 우선 순위 수준에서 휴면 상태인 경우 무시하라는 신호를 받으면 프로세스가 깨어나지만 longjmp를 수행하지 않으며 일반적으로 계속 휴면 상태에 있습니다. 하지만 사용자는 프로세스가 깨어났다는 느낌을 받지 않고 마치 신호가 발생하지 않은 것처럼 느낍니다.

네 번째로 주의할 점: 커널은 하위 프로세스 종료(SIGCLD) 신호를 다른 신호와 다르게 처리합니다. 프로세스가 자식 프로세스를 종료하라는 신호를 받았는지 확인하면 기본적으로 프로세스는 신호를 받지 못한 것처럼 동작합니다. 부모 프로세스가 시스템 호출 wait를 실행하면 해당 프로세스는 시스템 호출에서 깨어납니다. wait 및 Wait 호출로 돌아가서 일련의 대기 호출 후속 작업(좀비 자식 프로세스 찾기, 자식 프로세스의 프로세스 테이블 항목 해제)을 수행한 다음 wait에서 돌아옵니다. SIGCLD 신호의 기능은 인터럽트 가능한 우선순위 수준에서 잠들어 있는 프로세스를 깨우는 것입니다. 프로세스가 신호를 포착하면 일반 신호 처리와 마찬가지로 핸들러 루틴으로 이동합니다. 프로세스가 신호를 무시하면 시스템 호출 대기의 동작이 달라집니다. SIGCLD의 기능은 인터럽트 가능한 우선 순위 수준에서 잠자고 있는 프로세스를 깨우는 것뿐이므로 대기 호출을 실행하는 상위 프로세스가 깨어나 계속됩니다. 후속 작업을 실행한 다음 다른 하위 프로세스를 기다립니다.

프로세스가 시그널 시스템 호출을 호출하고 SIGCLD 처리 방법을 설정하고 프로세스에 좀비 상태의 하위 프로세스가 있는 경우 커널은 해당 프로세스에 SIGCLD 시그널을 보냅니다.

2. setjmp와 longjmp의 기능

앞서 신호 처리 메커니즘을 소개할 때 setjmp와 longjmp가 여러 번 언급되었지만 이들의 기능과 구현 방법은 자세히 설명되지 않았습니다. 이에 대한 간략한 소개는 다음과 같습니다.

신호를 도입할 때 호출이 완료될 때까지 기다리지 않고 신호가 수신되었는지 확인한 후 원래 시스템 호출에서 직접 반환하는 프로세스가 필요한 곳이 여러 곳 있었습니다. 프로세스가 갑자기 컨텍스트를 변경하는 이러한 상황은 setjmp 및 longjmp를 사용한 결과입니다. setjmp는 저장된 컨텍스트를 사용자 영역에 저장하고 이전 컨텍스트에서 계속 실행합니다. 즉, 프로세스가 리소스나 기타 이유로 절전 모드로 전환되면 커널이 해당 프로세스에 대해 setjmp를 실행하여 절전 모드에서 신호에 의해 깨어나고 프로세스가 다시 절전 모드로 전환될 수 없게 됩니다. , 커널은 프로세스에 대해 longjmp를 호출합니다. 이 작업은 커널이 원래 setjmp 호출에 의해 프로세스의 사용자 영역에 저장된 컨텍스트를 현재 컨텍스트로 복원하여 프로세스가 기다리기 전의 상태로 돌아갈 수 있도록 하기 위한 것입니다. 자원의 경우 커널은 setjmp에 대해 1을 반환하므로 프로세스는 시스템 호출이 실패했음을 알 수 있습니다. 그것이 그들이 하는 일입니다.

3. 시그널과 관련된 시스템 호출

신호에 대한 대부분의 지식은 이전 두 섹션에서 소개되었습니다. 이번 섹션에서는 이러한 시스템 호출에 대해 알아 보겠습니다. 그 중 시스템 호출 시그널은 프로세스에서 특정 시그널의 처리 방법을 설정하는 데 사용되고, 시스템 호출 kill은 지정된 프로세스에 시그널을 보내는 데 사용됩니다. 이 두 호출은 신호의 기본 작동을 형성합니다. 마지막 두 호출인 일시 중지 및 알람은 프로세스 일시 중지이며 호출 알람은 신호를 통해 타이머 만료 프로세스를 알리는 데 사용됩니다. 그래서 여기서는 이 두 가지 호출도 소개합니다.

1. 신호 시스템 호출

시스템 호출 신호는 특정 신호의 처리 방법을 설정하는 데 사용됩니다. 호출 선언의 형식은 다음과 같습니다.
void (*signal(int signum, void (*handler)(int)))(int);
이 호출을 사용하여 프로세스에 다음 헤더 파일을 추가합니다.
#포함

위 선언 형식은 상대적으로 복잡하며, 사용법을 모른다면 다음과 같은 유형 정의 형식(POSIX 정의)을 통해 사용할 수도 있습니다. typedef void (*sighandler_t)(int);
singandler_t 신호(int signum, singandler_t 핸들러);
하지만 이 형식은 시스템마다 유형 정의가 다르기 때문에 이 형식을 사용하려면 온라인 매뉴얼을 참조하는 것이 가장 좋습니다.

호출에서 매개변수 signum은 메서드를 처리하기 위해 설정되는 신호를 나타냅니다. 두 번째 매개변수 핸들러는 처리 함수입니다. 또는

SIG_IGN: 매개변수 signum이 가리키는 신호를 무시합니다.
SIG_DFL: 매개변수 signum이 가리키는 신호의 처리 방법을 기본값으로 복원합니다.

신호 처리 루틴에 전달되는 정수 매개변수는 신호 값이며, 이를 통해 하나의 신호 처리 루틴이 여러 신호를 처리할 수 있습니다. 시스템 호출 시그널의 반환 값은 지정된 시그널 signum의 이전 처리 루틴이거나, 오류 발생 시 반환되는 오류 코드 SIG_ERR입니다. 간단한 예를 살펴보겠습니다:

#include 
\#include 
\#include 
void sigroutine(int dunno) { /* 信号处理例程,其中dunno将会得到信号的值 */ 
switch (dunno) { 
case 1: 
printf("Get a signal -- SIGHUP "); 
break; 
case 2: 
printf("Get a signal -- SIGINT "); 
break; 
case 3: 
printf("Get a signal -- SIGQUIT "); 
break; 
} 
return; 
} 

int main() { 
printf("process id is %d ",getpid()); 
signal(SIGHUP, sigroutine); //* 下面设置三个信号的处理方法 
signal(SIGINT, sigroutine); 
signal(SIGQUIT, sigroutine); 
for (;;) ; 
} 

其中信号SIGINT由按下Ctrl-C发出,信号SIGQUIT由按下Ctrl-发出。该程序执行的结果如下:

localhost:~$ ./sig_test 
process id is 463 
Get a signal -SIGINT //按下Ctrl-C得到的结果 
Get a signal -SIGQUIT //按下Ctrl-得到的结果 
//按下Ctrl-z将进程置于后台 
[1]+ Stopped ./sig_test 
localhost:~$ bg 
[1]+ ./sig_test & 
localhost:~$ kill -HUP 463 //向进程发送SIGHUP信号 
localhost:~$ Get a signal – SIGHUP 
kill -9 463 //向进程发送SIGKILL信号,终止进程 
localhost:~$ 

2、kill 系统调用

系统调用kill用来向进程发送一个信号。该调用声明的格式如下:
int kill(pid_t pid, int sig);
在使用该调用的进程中加入以下头文件:

\#include 
\#include 

该 系统调用可以用来向任何进程或进程组发送任何信号。如果参数pid是正数,那么该调用将信号sig发送到进程号为pid的进程。如果pid等于0,那么信 号sig将发送给当前进程所属进程组里的所有进程。如果参数pid等于-1,信号sig将发送给除了进程1和自身以外的所有进程。如果参数pid小于- 1,信号sig将发送给属于进程组-pid的所有进程。如果参数sig为0,将不发送信号。该调用执行成功时,返回值为0;错误时,返回-1,并设置相应 的错误代码errno。下面是一些可能返回的错误代码:
EINVAL:指定的信号sig无效。
ESRCH:参数pid指定的进程或进程组不存在。注意,在进程表项中存在的进程,可能是一个还没有被wait收回,但已经终止执行的僵死进程。
EPERM: 进程没有权力将这个信号发送到指定接收信号的进程。因为,一个进程被允许将信号发送到进程pid时,必须拥有root权力,或者是发出调用的进程的UID 或EUID与指定接收的进程的UID或保存用户ID(savedset-user-ID)相同。如果参数pid小于-1,即该信号发送给一个组,则该错误 表示组中有成员进程不能接收该信号。

3、pause系统调用

系统调用pause的作用是等待一个信号。该调用的声明格式如下:
int pause(void);
在使用该调用的进程中加入以下头文件:
#include

该调用使得发出调用的进程进入睡眠,直到接收到一个信号为止。该调用总是返回-1,并设置错误代码为EINTR(接收到一个信号)。下面是一个简单的范例:

#include 
\#include 
\#include 
void sigroutine(int unused) { 
printf("Catch a signal SIGINT "); 
} 

int main() { 
signal(SIGINT, sigroutine); 
pause(); 
printf("receive a signal "); 
} 

在这个例子中,程序开始执行,就象进入了死循环一样,这是因为进程正在等待信号,当我们按下Ctrl-C时,信号被捕捉,并且使得pause退出等待状态。

4、alarm和 setitimer系统调用

系统调用alarm的功能是设置一个定时器,当定时器计时到达时,将发出一个信号给进程。该调用的声明格式如下:
unsigned int alarm(unsigned int seconds);
在使用该调用的进程中加入以下头文件:
#include

系 统调用alarm安排内核为调用进程在指定的seconds秒后发出一个SIGALRM的信号。如果指定的参数seconds为0,则不再发送 SIGALRM信号。后一次设定将取消前一次的设定。该调用返回值为上次定时调用到发送之间剩余的时间,或者因为没有前一次定时调用而返回0。

注意,在使用时,alarm只设定为发送一次信号,如果要多次发送,就要多次使用alarm调用。

对于alarm,这里不再举例。现在的系统中很多程序不再使用alarm调用,而是使用setitimer调用来设置定时器,用getitimer来得到定时器的状态,这两个调用的声明格式如下:
int getitimer(int which, struct itimerval *value);
int setitimer(int which, const struct itimerval *value, struct itimerval *ovalue);
在使用这两个调用的进程中加入以下头文件:
#include

该系统调用给进程提供了三个定时器,它们各自有其独有的计时域,当其中任何一个到达,就发送一个相应的信号给进程,并使得计时器重新开始。三个计时器由参数which指定,如下所示:
TIMER_REAL:按实际时间计时,计时到达将给进程发送SIGALRM信号。
ITIMER_VIRTUAL:仅当进程执行时才进行计时。计时到达将发送SIGVTALRM信号给进程。
ITIMER_PROF:当进程执行时和系统为该进程执行动作时都计时。与ITIMER_VIR-TUAL是一对,该定时器经常用来统计进程在用户态和内核态花费的时间。计时到达将发送SIGPROF信号给进程。

定时器中的参数value用来指明定时器的时间,其结构如下:

struct itimerval { 
struct timeval it_interval; /* 下一次的取值 */ 
struct timeval it_value; /* 本次的设定值 */ 
}; 

该结构中timeval结构定义如下: 
struct timeval { 
long tv_sec; /* 秒 */ 
long tv_usec; /* 微秒,1秒 = 1000000 微秒*/ 
}; 

在setitimer 调用中,参数ovalue如果不为空,则其中保留的是上次调用设定的值。定时器将it_value递减到0时,产生一个信号,并将it_value的值设 定为it_interval的值,然后重新开始计时,如此往复。当it_value设定为0时,计时器停止,或者当它计时到期,而it_interval 为0时停止。调用成功时,返回0;错误时,返回-1,并设置相应的错误代码errno:
EFAULT:参数value或ovalue是无效的指针。
EINVAL:参数which不是ITIMER_REAL、ITIMER_VIRT或ITIMER_PROF中的一个。

下面是关于setitimer调用的一个简单示范,在该例子中,每隔一秒发出一个SIGALRM,每隔0.5秒发出一个SIGVTALRM信号:

#include 
\#include 
\#include 
\#include 
int sec; 

void sigroutine(int signo) { 
switch (signo) { 
case SIGALRM: 
printf("Catch a signal -- SIGALRM "); 
break; 
case SIGVTALRM: 
printf("Catch a signal -- SIGVTALRM "); 
break; 
} 
return; 
} 

int main() { 
struct itimerval value,ovalue,value2; 
sec = 5; 

printf("process id is %d ",getpid()); 
signal(SIGALRM, sigroutine); 
signal(SIGVTALRM, sigroutine); 

value.it_value.tv_sec = 1; 
value.it_value.tv_usec = 0; 
value.it_interval.tv_sec = 1; 
value.it_interval.tv_usec = 0; 
setitimer(ITIMER_REAL, &value, &ovalue); 

value2.it_value.tv_sec = 0; 
value2.it_value.tv_usec = 500000; 
value2.it_interval.tv_sec = 0; 
value2.it_interval.tv_usec = 500000; 
setitimer(ITIMER_VIRTUAL, &value2, &ovalue); 

for (;;) ; 
} 

该例子的屏幕拷贝如下:

localhost:~$ ./timer_test 
process id is 579 
Catch a signal – SIGVTALRM 
Catch a signal – SIGALRM 
Catch a signal – SIGVTALRM 
Catch a signal – SIGVTALRM 
Catch a signal – SIGALRM 
Catch a signal –GVTALRM

通过本文,你应该对 Linux 下的信号机制有了一个深入的了解,知道了它的定义、原理、用法和优缺点。你也应该明白了信号机制的作用和影响,以及如何在 Linux 下正确地使用和处理信号。我们建议你在使用 Linux 系统时,使用信号机制来提高系统的响应性和灵活性。同时,我们也提醒你在使用信号机制时要注意一些潜在的问题和挑战,如信号丢失、信号屏蔽、信号安全等。希望本文能够帮助你更好地使用 Linux 系统,让你在 Linux 下掌握信号机制的使用和处理。

위 내용은 Linux에서의 신호 메커니즘: 프로세스 간 통신 및 제어를 위해 신호를 사용하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 lxlinux.net에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제