티스토리 뷰

728x90
반응형
리눅스 C++ Signal Handler 클래스 구현

리눅스 C++ Signal 핸들러 클래스 (멀티스레드 기반)

1. 개요

이 문서는 리눅스 환경에서 시그널 처리 전용 클래스를 만들고, 별도의 스레드에서 안전하게 시그널을 처리하는 구조를 설명합니다.

2. 핵심 설계

  • 시그널과 콜백을 등록하는 유연한 클래스 구조
  • 핸들링은 별도 스레드에서 sigwaitinfo()로 처리
  • 메인 스레드는 자유롭게 동작 가능

3. 클래스 헤더: SignalHandler.hpp

#pragma once

#include <functional>
#include <map>
#include <thread>
#include <atomic>
#include <csignal>
#include <set>

class SignalHandler {
public:
    using Callback = std::function<void(int, siginfo_t*)>;

    SignalHandler();
    ~SignalHandler();

    bool registerSignal(int signal, Callback cb);
    void start();
    void stop();

private:
    void signalThreadFunc();

    std::map<int, Callback> _callbacks;
    std::set<int> _registeredSignals;

    std::thread _signalThread;
    std::atomic<bool> _running;
};

4. 클래스 구현: SignalHandler.cpp

#include "SignalHandler.hpp"
#include <iostream>
#include <cstring>
#include <unistd.h>
#include <pthread.h>

SignalHandler::SignalHandler()
    : _running(false) {}

SignalHandler::~SignalHandler() {
    stop();
}

bool SignalHandler::registerSignal(int signal, Callback cb) {
    _callbacks[signal] = cb;
    _registeredSignals.insert(signal);
    return true;
}

void SignalHandler::start() {
    if (_running) return;

    _running = true;

    sigset_t signalSet;
    sigemptyset(&signalSet);
    for (int sig : _registeredSignals) {
        sigaddset(&signalSet, sig);
    }

    if (pthread_sigmask(SIG_BLOCK, &signalSet, nullptr) != 0) {
        perror("pthread_sigmask");
        return;
    }

    _signalThread = std::thread(&nxcSignalHandler::signalThreadFunc, this);
}

void SignalHandler::stop() {
    if (!_running) return;

    _running = false;
    pthread_kill(_signalThread.native_handle(), SIGINT);
    if (_signalThread.joinable()) {
        _signalThread.join();
    }
}

void SignalHandler::signalThreadFunc() {
    sigset_t signalSet;
    sigemptyset(&signalSet);
    for (int sig : _registeredSignals) {
        sigaddset(&signalSet, sig);
    }

    while (_running) {
        siginfo_t info;
        int sig = sigwaitinfo(&signalSet, &info);
        if (sig > 0) {
            auto it = _callbacks.find(sig);
            if (it != _callbacks.end()) {
                it->second(sig, &info);
            } else {
                std::cerr << "[nxcSignalHandler] No handler for signal: " << sig << std::endl;
            }
        }
    }
}

5. 사용 예시: main.cpp

#include "SignalHandler.hpp"
#include <iostream>
#include <unistd.h>

int main() {
    std::cout << "[Main] PID: " << getpid() << std::endl;

    SignalHandler handler;

    handler.registerSignal(SIGUSR1, [](int sig, siginfo_t* info) {
        std::cout << "[Handler] Received SIGUSR1 from PID: " << info->si_pid << std::endl;
    });

    handler.registerSignal(SIGINT, [](int, siginfo_t*) {
        std::cout << "[Handler] SIGINT received. Exiting." << std::endl;
        exit(0);
    });

    handler.start();

    while (true) {
        std::cout << "[Main] Working..." << std::endl;
        sleep(2);
    }

    return 0;
}

6. 빌드 명령

g++ -std=c++17 -pthread -o app main.cpp nxcSignalHandler.cpp

7. 장점 요약

  • 별도 스레드에서 안전하게 시그널 처리
  • 메인 스레드와 격리된 구조
  • 콜백 방식으로 유연한 시그널 관리
💡 확장 아이디어:
  • SIGCHLD, SIGTERM 등도 등록 가능
  • 콜백에서 작업 큐와 연동하여 비동기 처리 가능
  • sigqueue()로 사용자 데이터 수신 처리 추가 가능
728x90
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/04   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30
글 보관함
반응형