サブスレッドからメインスレッドにだけシグナルを送りたい


```cpp:a.cpp

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

#include <cstdio>
#include <cstring>
#include <mutex>
#include <thread>
#include <map>
#include <random>

typedef void(*Handler_func)(int);

void sig_handler(int) {
}

int check_signal() {
    sigset_t ss;
    sigemptyset(&ss);
    sigaddset(&ss, SIGTERM);
    sigaddset(&ss, SIGUSR1);
    
    timespec ts;
    ts.tv_sec = 0;
    ts.tv_nsec = 0;
    int sig = sigtimedwait(&ss, nullptr, &ts);
    if (sig > 0) {
        return sig;
    } else {
        if (errno != EAGAIN) {
            char buf[1024];
            char *bufp = strerror_r(errno, buf, 1024);
            printf("sigtimedwait fail. %s\n", bufp);
            return -1;
        }
    }
    return 0;
}

int set_sigprocmask() {
    sigset_t newss;
    sigemptyset(&newss);
    sigaddset(&newss, SIGCHLD);
    sigaddset(&newss, SIGUSR1);
    sigaddset(&newss, SIGALRM);
    sigaddset(&newss, SIGHUP);
    sigaddset(&newss, SIGINT);
    sigaddset(&newss, SIGQUIT);
    sigaddset(&newss, SIGTERM);
    if (sigprocmask(SIG_BLOCK, &newss, nullptr)) {
        return 1;
    } else {
        return 0;
    }
}

int set_sigaction(int sig, Handler_func func) {
    struct sigaction sa;
    memset(&sa, 0, sizeof(struct sigaction));
    sa.sa_handler = func;
    sigemptyset(&sa.sa_mask);
    if (sigaction(sig, &sa, nullptr)) {
        return 1;
    } else {
        return 0;
    }
}

int set_sigaction_ign(int sig) {
    struct sigaction sa;
    memset(&sa, 0, sizeof(struct sigaction));
    sa.sa_handler = SIG_IGN;
    sigemptyset(&sa.sa_mask);
    if (sigaction(sig, &sa, nullptr)) {
        return 1;
    } else {
        return 0;
    }
}

int init_signal() {
    set_sigaction(SIGCHLD, &sig_handler);
    set_sigaction(SIGUSR1, &sig_handler);
    set_sigaction(SIGALRM, &sig_handler);
    set_sigaction(SIGHUP, &sig_handler);
    set_sigaction(SIGINT, &sig_handler);
    set_sigaction(SIGQUIT, &sig_handler);
    set_sigaction(SIGTERM, &sig_handler);
    set_sigaction_ign(SIGPIPE);
    if (set_sigprocmask()) {
        return 1;
    } else {
        return 0;
    }
}

class th_info {
    public:
        std::thread th;
        pthread_t main_pthread_t;
};

void thread_func(std::mutex &mtx, std::map<int, th_info> &ths, int num) {
    // 親の生み出し処理中は止まる
    mtx.lock();
    mtx.unlock();
    
    std::random_device rd;
    std::mt19937 mt(rd());
    std::uniform_int_distribution<int> wait_time(1, 10);
    
    while (!check_signal()) {
        sleep(wait_time(mt));
        printf("[%d]: send SIGUSR1.\n", num);
        mtx.lock();
        pthread_kill(ths[num].main_pthread_t, SIGUSR1);
        mtx.unlock();
    }
}

void main_thread(std::mutex &mtx, std::map<int, th_info> &ths) {
    sigset_t ss;
    sigemptyset(&ss);
    sigaddset(&ss, SIGHUP);
    sigaddset(&ss, SIGTERM);
    sigaddset(&ss, SIGINT);
    sigaddset(&ss, SIGQUIT);
    sigaddset(&ss, SIGUSR1);
    while (1) {
        int sig;
        sigwait(&ss, &sig);
        if (sig == SIGUSR1) {
            printf("recv SIGUSR1.\n");
        } else {
            printf("recv FINISH SIGNAL.\n");
            break;
        }
    }
    // サブスレッドを回収する
    mtx.lock();
    for (auto &it : ths) {
        pthread_kill(it.second.th.native_handle(), SIGUSR1);
    }
    mtx.unlock();
    for (auto &it : ths) {
        it.second.th.join();
    }
}

void gen_thread(std::mutex &mtx, std::map<int, th_info> &ths) {
    pthread_t main_pthread_t = pthread_self();
    mtx.lock();
    for (int i = 0; i < 3; ++i) {
        std::thread th(thread_func, std::ref(mtx), std::ref(ths), i);
        ths[i].th = std::move(th);
        ths[i].main_pthread_t = main_pthread_t;
    }
    mtx.unlock();
}

int main(int, char **) {
    if (init_signal()) {
        printf("init_signal fail.\n");
        return 1;
    }
    
    std::mutex mtx;
    std::map<int, th_info> ths;
    
    gen_thread(mtx, ths);
    main_thread(mtx, ths);
    
    return 0;
}

```

<pre>
[root@localhost ~]# g++ --std=c++11 a.cpp -lpthread
[root@localhost ~]#
[root@localhost ~]# ./a.out
[1]: send SIGUSR1.
recv SIGUSR1.
[2]: send SIGUSR1.
recv SIGUSR1.
[0]: send SIGUSR1.
recv SIGUSR1.
[1]: send SIGUSR1.
recv SIGUSR1.
[2]: send SIGUSR1.
recv SIGUSR1.
[2]: send SIGUSR1.
recv SIGUSR1.
[0]: send SIGUSR1.
recv SIGUSR1.
^Crecv FINISH SIGNAL.
[1]: send SIGUSR1.
[2]: send SIGUSR1.
[0]: send SIGUSR1.
[root@localhost ~]#
</pre>
スレッドを生み出す前に、メインスレッドでpthread_self()を実行して、
それを保存しておけば良い。

サブスレッド側で、メインスレッドに何かを通知したい場合、
pthread_kill(main_pthread_t, SIGUSR1);
という具合に通知できる。

シグナル関連の設定を、あらかじめハンドラをセットした上で
ブロックしておかないと、うまく動かない。

スレッドにした時点で、可能な限りsigwait等を使って、
ハンドラが動作しないようにする。
（なので、プログラム終了時に、サブスレッドが単にsleepで寝ているが、
　これらは割り込み処理で抜けることは無く、渡した秒数待ってから終了する）

ひとまず動作するコードにすると、なんだか長くなる・・・。うーん。


2015/12/10 追記

どうにも動作見ていると、メインスレッドに対してシグナルを送ると、
他のスレッドも受信している・・・。

メインスレッドだけがsigwaitでシグナルを捕捉すればよいけど、
他のスレッドもsigwaitで待っていると、
メインスレッドも他のスレッドも、sigwaitから返ってきてしまう・・・。

うーん、サブスレッド -> メインスレッドに送るシグナルを別途決めて、
サブスレッド側で、そのシグナルを待つようなことをしなければ解決だけど。。

もっとスマートに、決めうちでメインスレッドにだけ、シグナルを送れないものかな・・・。


、、、pthread_killでシグナル送るために、メインスレッドのpthread_tを保存したけど、
結局のところ、kill(メインスレッドのpid, SIGUSR1);という処理と同等な模様。

うーん。