如何使用SIGINT在第二个线程中中断getchar

问题描述 投票:0回答:1

我需要在我的控制台应用程序中处理SIGINT,我发现了许多有关sa_flags = 0的示例; sigaction结构-这意味着getchar将被中止并返回-1。但这不适用于多线程

看我的代码


int p[2];
FILE *stdin_writer = nullptr;

void int_handler(int signum)
{
    //////do nothing

    //////or write something into stdin..... also no help

    //write(fileno(stdin), s, sizeof s - 1);

    //////using pipes deadlocks application

    //stdin_writer = fdopen(p[1], "w");
    //fputc('g', stdin_writer);
}

void run()
{

    //pipe(p);
    //dup2(p[0], STDIN_FILENO);

    printf("before getchar\n");
    auto c = getchar();
    printf("after getchar\n");
}

int main()
{
    //////Setup SIGINT handler

    struct sigaction sh;

    sh.sa_handler = int_handler;
    sigemptyset(&sh.sa_mask);
    sh.sa_flags = 0;
    sigaction(SIGINT, &sh, NULL);
    return 0;

    //////Setup console

    termios _prev{ 0 };
    // grab old terminal i/o settings
    tcgetattr(0, &_prev);
    // make new settings same as old settings 
    auto current = _prev;
    // disable buffered i/o
    current.c_lflag &= ~ICANON;
    // set no echo mode
    current.c_lflag &= ~ECHO;

    // use these new terminal i/o settings now
    tcsetattr(0, TCSANOW, &current);

    std::thread trd(&run);

    trd.join();
} 

我想在Ctrl + C上中断getchar-类似的代码在单线程版本(没有std :: thread东西)下工作正常,但在多线程中却行不通。任何人都请帮助我-我已经整日陷入这个问题

c++ linux multithreading console stdin
1个回答
0
投票

最后我找到了正确的解决方案。仅当此信号与getchar发送到同一线程时,SIGINT信号才会中断getchar操作。因此,如果您的应用程序有大量线程-我们遇到的情况是,在正确的线程中捕获SIGINT的可能性很小。因此,您将无限期地等待getchar。...

但是!如果我们会认真阅读有关pthread_kill函数的pthread文档,我们可以看到此行

pthread_kill-向线程发送信号

pthread_kill-实际上不会杀死线程,它是发送信号。尤里卡!我们可以将信号SIGINT重新发送到正确的线程中。参见下面的代码

std::optional<std::thread> trd;
std::mutex mtx;

void int_handler(int signum)
{
    std::lock_guard lk(mtx);
    if (trd && std::this_thread::get_id() != trd->get_id())
        pthread_kill(trd->native_handle(), signum);
}

void run()
{
    printf("before getchar\n");
    auto c = getchar();
    printf("after getchar\n");
}

int main()
{
    //////Setup SIGINT handler

    struct sigaction sh;

    sh.sa_handler = int_handler;
    sigemptyset(&sh.sa_mask);
    sh.sa_flags = 0;
    sigaction(SIGINT, &sh, NULL);
    return 0;

    //////Setup console

    termios _prev{ 0 };
    // grab old terminal i/o settings
    tcgetattr(0, &_prev);
    // make new settings same as old settings 
    auto current = _prev;
    // disable buffered i/o
    current.c_lflag &= ~ICANON;
    // set no echo mode
    current.c_lflag &= ~ECHO;

    // use these new terminal i/o settings now
    tcsetattr(0, TCSANOW, &current);

    {
        std::lock_guard lk(mtx);
        trd.emplace(&run);
    }

    trd->join();
} 
© www.soinside.com 2019 - 2024. All rights reserved.