수색…


통사론

  • 부호없는 경보 (부호없는 초);
  • int kill (pid_t pid, int sig);

매개 변수

함수, 매개 변수, 반환 값 기술
alarm() 함수 이름
unsigned seconds 경보를 발생시키는 초 또는 보류중인 경보를 취소하기위한 0
> = 0 보류중인 다른 알람이 없으면 0이고 그렇지 않은 경우에는 보류중인 알람이 아직 열린 시간 (초)입니다. 이 기능은 실패하지 않습니다.
- -
kill() 함수 이름
pid_t pid .
int sig 0 또는 신호 ID
0, -1 성공시 0이 반환되고, errnoEINVAL , EPERM 또는 ESRCH 로 설정하면 실패시 -1이 반환됩니다.

기본 동작으로 SIGALARM 높이기

alarm 사용하여 지정된 간격 후에 SIGALARM 신호를 발생 시키도록 예약 할 수 있습니다. 사용자가이 신호에 대해 명시 적 신호 처리기를 차단, 무시 또는 지정하지 않은 경우이 신호의 기본 동작은 도착시 수행됩니다. 스펙 별 SIGALARM 기본 조치는 프로세스를 종료하는 것입니다.

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

int main (int argc, char** argv)
{
    printf("Hello!\n");

    // Set the alarm for five second
    alarm(5); // Per POSIX, this cannot fail

    // Now sleep for 15 seconds
    for (int i = 1; i <= 15; i++)
    {
        printf("%d\n", i);
        sleep(1);
    }

    // And print the message before successful exit
    printf("Goodbye!\n");

    return EXIT_SUCCESS;
}

이 결과는 다음과 같습니다.

Hello!
1
2
3
4
5
[2]    35086 alarm      ./a.out

sigaction을 사용하여 신호 처리기 설정 및 raise를 사용하여 신호 높이기

프로그램이 기본 동작을 사용하지 않고 특정 신호에 반응하려면 sigaction 사용하여 사용자 정의 신호 처리기를 설치할 수 있습니다. sigaction 은 3 개의 인자를받습니다 - 행동 할 시그널, sigaction_t 구조체에 대한 포인터, NULL 이 아니라면 새로운 행동과 sigaction_t 포인터를 기술 NULL 이 아니라면 이전 행동으로 채워질 것입니다. raise 프로세스를 사용하면 동일한 프로세스에서 신호를 발생시킬 수 있습니다. 더 많은 제어가 필요한 경우 (다른 프로세스로 신호를 보내려면 kill 또는 pthread_kill 사용할 수 있으며 대상 프로세스 ID 또는 스레드 ID를 사용할 수 있음).

#include <unistd.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// Signals are numbered from 1, signal 0 doesn't exist
volatile sig_atomic_t last_received_signal = 0;

// Signal handler, will set the global variable
// to indicate what is the last signal received.
// There should be as less work as possible inside
// signal handler routine, and one must take care only
// to call reentrant functions (in case of signal arriving
// while program is already executing same function)
void signal_catcher(int signo, siginfo_t *info, void *context)
{
    last_received_signal = info->si_signo;
}

int main (int argc, char** argv)
{
    // Setup a signal handler for SIGUSR1 and SIGUSR2
    struct sigaction act;
    memset(&act, 0, sizeof act);

    // sigact structure holding old configuration
    // (will be filled by sigaction):
    struct sigaction old_1;
    memset(&old_1, 0, sizeof old_1);
    struct sigaction old_2;
    memset(&old_2, 0, sizeof old_2);

    act.sa_sigaction = signal_catcher;
    // When passing sa_sigaction, SA_SIGINFO flag
    // must be specified. Otherwise, function pointed
    // by act.sa_handler will be invoked
    act.sa_flags = SA_SIGINFO;

    if (0 != sigaction(SIGUSR1, &act, &old_1))
    {
        perror("sigaction () failed installing SIGUSR1 handler");
        return EXIT_FAILURE;
    }

    if (0 != sigaction(SIGUSR2, &act, &old_2))
    {
        perror("sigaction() failed installing SIGUSR2 handler");
        return EXIT_FAILURE;
    }

    // Main body of "work" during which two signals
    // will be raised, after 5 and 10 seconds, and which
    // will print last received signal
    for (int i = 1; i <= 15; i++)
    {
        if (i == 5)
        {
            if (0 != raise(SIGUSR1))
            {
                perror("Can't raise SIGUSR1");
                return EXIT_FAILURE;
            }
        }

        if (i == 10)
        {
            if (0 != raise(SIGUSR2))
            {
                perror("Can't raise SIGUSR2");
                return EXIT_FAILURE;
            }
        }

        printf("Tick #%d, last caught signal: %d\n",
            i, last_received_signal);

        sleep(1);
    }

    // Restore old signal handlers
    if (0 != sigaction(SIGUSR1, &old_1, NULL))
    {
        perror("sigaction() failed restoring SIGUSR1 handler");
        return EXIT_FAILURE;
    }

    if (0 != sigaction(SIGUSR2, &old_2, NULL))
    {
        perror("sigaction() failed restoring SIGUSR2 handler");
        return EXIT_FAILURE;
    }

    return EXIT_SUCCESS;
}

이 결과는 다음과 같습니다.

Tick #1, last caught signal: 0
Tick #2, last caught signal: 0
Tick #3, last caught signal: 0
Tick #4, last caught signal: 0
Tick #5, last caught signal: 30
Tick #6, last caught signal: 30
Tick #7, last caught signal: 30
Tick #8, last caught signal: 30
Tick #9, last caught signal: 30
Tick #10, last caught signal: 31
Tick #11, last caught signal: 31
Tick #12, last caught signal: 31
Tick #13, last caught signal: 31
Tick #14, last caught signal: 31
Tick #15, last caught signal: 31

kill ()을 사용하여 자살하는 프로세스

프로세스는 kill() 함수를 사용하여 다른 프로세스로 신호를 보낼 수 있습니다.

이렇게하려면 보내는 프로세스가 수신 프로세스의 PID를 알고 있어야합니다. 경주를 도입하지 않고 프로세스는 자신의 PID (그리고 그 자식의 PID)만이 알 수 있으므로 kill() 의 사용법을 보여주기위한 가장 간단한 예제는 프로세스가 자신에게 신호를 보내는 것입니다.

kill 신호 ( SIGKILL )를 보내어 자체 종료를 시작하는 프로세스의 예는 다음과 같습니다.

#define _POSIX_C_SOURCE 1

#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
#include <stdio.h>


int main (void)
{
  pid_t pid = getpid(); /* Get my iown process ID. */

  kill(pid, SIGKILL); /* Send myself a KILL signal. */

  puts("Signal delivery initiated.");  /* Although not guaranteed, 
                                  practically the program never gets here. */

  pause(); /* Wait to die. */

  puts("This never gets printed.");
}

산출:

Killed

(... 구현에 따라 비슷하게)

thread-safe 방식으로 write ()에 의해 생성 된 SIGPIPE 처리

읽기 끝이 닫혀있는 명명 된 파이프 또는 스트림 소켓에 대해 write() 가 호출되면 다음 두 가지 일이 발생합니다.

POSIX.1-2001
  1. SIGPIPE 시그널은 write() 를 호출 한 프로세스 로 보내진다.
POSIX.1-2004
  1. SIGPIPE 신호는 write() 를 호출 한 쓰레드 로 보내진다.
  1. EPIPE 오류는 write() 의해 반환됩니다.

SIGPIPE 를 다루는 방법에는 여러 가지가 있습니다.

  • 소켓의 경우 Linux의 경우 MSG_NOSIGNAL , BSD의 SO_NOSIGPIPE 와 같은 플랫폼 관련 옵션을 설정하여 SIGPIPE 비활성화 할 수 있습니다 ( send 전용으로 작동하지만 write 에는 사용할 수 없음). 이것은 휴대용이 아닙니다.
  • FIFO (명명 된 파이프)의 경우 작성자가 O_WRONLY 대신 O_RDWR 사용하면 읽기 끝이 항상 열리도록 SIGPIPE 가 생성되지 않습니다. 그러나 이것은 EPIPE 도 비활성화합니다.
  • 우리는 SIGPIPE 를 무시하거나 글로벌 핸들러를 설정할 수있다. 이것은 좋은 해결책이지만 전체 애플리케이션을 제어하지 않으면 (예 : 라이브러리 작성) 허용되지 않습니다.
  • 최근 POSIX 버전에서는 SIGPIPEwrite() 를 호출 한 스레드로 보내고 동기 신호 처리 기술을 사용하여 처리한다는 사실을 사용할 수 있습니다.

아래 코드는 POSIX.1-2004 및 이후 버전에 대한 스레드 안전 SIGPIPE 처리를 보여줍니다.

이 게시물 에서 영감을 얻었 습니다 .

  • 우선, pthread_sigmask() 사용하여 현재 쓰레드의 시그널 마스크에 SIGPIPE 를 추가 pthread_sigmask() .
  • 이미 sigpending() 사용하여 보류중인 SIGPIPE 가 있는지 확인하십시오.
  • write() 호출하십시오. 판독 끝이 닫히면 보류중인 신호 마스크에 SIGPIPE 가 추가되고 EPIPE 가 반환됩니다.
  • write() EPIPE 리턴했고, write() 전에 SIGPIPE 가 아직 보류 중이 아니면, sigtimedwait() 사용하여 보류중인 신호 마스크에서 제거하십시오.
  • pthread_sigmask() 사용하여 원래의 신호 마스크를 복구하십시오.

소스 코드:

#include <unistd.h>
#include <time.h>
#include <errno.h>
#include <sys/signal.h>

ssize_t safe_write(int fd, const void* buf, size_t bufsz)
{
    sigset_t sig_block, sig_restore, sig_pending;

    sigemptyset(&sig_block);
    sigaddset(&sig_block, SIGPIPE);

    /* Block SIGPIPE for this thread.
     *
     * This works since kernel sends SIGPIPE to the thread that called write(),
     * not to the whole process.
     */
    if (pthread_sigmask(SIG_BLOCK, &sig_block, &sig_restore) != 0) {
        return -1;
    }

    /* Check if SIGPIPE is already pending.
     */
    int sigpipe_pending = -1;
    if (sigpending(&sig_pending) != -1) {
        sigpipe_pending = sigismember(&sig_pending, SIGPIPE);
    }

    if (sigpipe_pending == -1) {
        pthread_sigmask(SIG_SETMASK, &sig_restore, NULL);
        return -1;
    }

    ssize_t ret;
    while ((ret = write(fd, buf, bufsz)) == -1) {
        if (errno != EINTR)
            break;
    }

    /* Fetch generated SIGPIPE if write() failed with EPIPE.
     *
     * However, if SIGPIPE was already pending before calling write(), it was
     * also generated and blocked by caller, and caller may expect that it can
     * fetch it later. Since signals are not queued, we don't fetch it in this
     * case.
     */
    if (ret == -1 && errno == EPIPE && sigpipe_pending == 0) {
        struct timespec ts;
        ts.tv_sec = 0;
        ts.tv_nsec = 0;

        int sig;
        while ((sig = sigtimedwait(&sig_block, 0, &ts)) == -1) {
            if (errno != EINTR)
                break;
        }
    }

    pthread_sigmask(SIG_SETMASK, &sig_restore, NULL);
    return ret;
}


Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow