Как отправить сигнал процессу в Linux с помощью C++?

Ответ

В Linux для отправки сигналов используется системный вызов kill() (из <csignal>). Основной способ:

#include <csignal>
#include <sys/types.h>
#include <unistd.h>
#include <iostream>

int main() {
    pid_t target_pid = 12345; // PID целевого процесса

    // 1. Отправка сигнала завершения (можно перехватить)
    if (kill(target_pid, SIGTERM) == -1) {
        perror("kill(SIGTERM) failed");
    }

    // 2. Отправка сигнала, который нельзя игнорировать (SIGKILL)
    // kill(target_pid, SIGKILL);

    // 3. Отправка сигнала текущему процессу
    raise(SIGUSR1); // Эквивалентно kill(getpid(), SIGUSR1)

    // 4. Проверка существования процесса (сигнал 0)
    if (kill(target_pid, 0) == 0) {
        std::cout << "Process " << target_pid << " exists and we have permission." << std::endl;
    } else {
        if (errno == ESRCH) {
            std::cout << "Process does not exist." << std::endl;
        } else if (errno == EPERM) {
            std::cout << "No permission to send signal." << std::endl;
        }
    }
    return 0;
}

Важные технические детали:

  • Права: Чтобы отправить сигнал, ваш процесс должен иметь соответствующие права (обычно быть владельцем процесса или иметь права root).
  • SIGKILL (9) и SIGSTOP (19): Эти сигналы не могут быть перехвачены, проигнорированы или заблокированы процессом-получателем.
  • Безопасность в многопоточных программах: В многопоточном приложении kill() отправляет сигнал всему процессу. Чтобы отправить сигнал конкретному потоку, используйте pthread_kill().
  • Более современный C++ интерфейс (C++11): Для управления сигналами внутри программы можно использовать std::signal, но для межпроцессного взаимодействия kill() остаётся стандартом.
  • Альтернативы сигналам: Для сложной межпроцессной коммуникации часто предпочтительнее использовать именованные каналы (FIFO), сокеты домена Unix (Unix domain sockets) или очереди сообщений POSIX, так как они более структурированы и надёжны.

Ответ 18+ 🔞

Э, слушай, вот сидишь ты, пишешь свой код, и вдруг — бац! — нужно какому-то процессу намекнуть, что пора бы и честь знать. Ну или просто проверить, жив ли он ещё. В Linux для этого есть старый добрый системный вызов kill(). Да-да, название обманчивое, он не только убивать умеет, он вообще сигналы слать может, любые. Ёпта, назвали бы send_signal() и не было бы путаницы.

Вот смотри, как это работает, на пальцах. Берёшь и пишешь:

#include <csignal>
#include <sys/types.h>
#include <unistd.h>
#include <iostream>

int main() {
    pid_t target_pid = 12345; // PID целевого процесса

    // 1. Отправка сигнала завершения (можно перехватить)
    if (kill(target_pid, SIGTERM) == -1) {
        perror("kill(SIGTERM) failed");
    }

    // 2. Отправка сигнала, который нельзя игнорировать (SIGKILL)
    // kill(target_pid, SIGKILL);

    // 3. Отправка сигнала текущему процессу
    raise(SIGUSR1); // Эквивалентно kill(getpid(), SIGUSR1)

    // 4. Проверка существования процесса (сигнал 0)
    if (kill(target_pid, 0) == 0) {
        std::cout << "Process " << target_pid << " exists and we have permission." << std::endl;
    } else {
        if (errno == ESRCH) {
            std::cout << "Process does not exist." << std::endl;
        } else if (errno == EPERM) {
            std::cout << "No permission to send signal." << std::endl;
        }
    }
    return 0;
}

Теперь по пунктам, а то подозрение ебать чувствую, что не всё понятно.

Во-первых, права. Не любой процесс может любому другому сигнал послать. Ты либо должен быть его владельцем, либо королём системы — рутом. Иначе получишь отлуп, и правильно. Доверия ебать ноль в современных системах к таким вещам.

Во-вторых, есть два священных монстра: SIGKILL (это девятка) и SIGSTOP. Это как мама, которая говорит «всё, хватит». Процесс не может их перехватить, проигнорировать или заблокировать. Это хуй с горы, который всех рассудит. Хочешь гарантированно прибить зависший процесс — шли девятку.

В-третьих, если у тебя программа многопоточная, тут начинается ёперный театр. Функция kill() шлёт сигнал всему процессу целиком. А если тебе нужно ткнуть пальцем в конкретный поток, то это уже pthread_kill(). Не перепутай, а то будет тебе хиросима и нигерсраки в рантайме.

Ещё есть в C++11 свой интерфейс, std::signal, но он больше для внутренней кухни, когда ты сам себе сигналы ловишь. А чтобы соседу по памяти настучать, kill() — это классика, манда с ушами, но работает.

И главное, чувак, запомни: сигналы — это как кричать через стену. Быстро, дёшево, но понять, что именно тебе кричат, сложно. Для нормального, вменяемого общения между процессами есть инструменты понадёжнее: именованные каналы, юникс-сокеты, очереди сообщений. Это уже как полноценный разговор, а не пинок под зад. Но если нужно просто и быстро — kill() твой друг. Только аккуратно, ходишь по охуенно тонкому льду с этими правами и номерами сигналов.