C++ 如何使用SIGINT中断第二个线程中的getchar

C++ 如何使用SIGINT中断第二个线程中的getchar,c++,linux,multithreading,console,stdin,C++,Linux,Multithreading,Console,Stdin,我需要在我的控制台应用程序中处理SIGINT,我发现了许多关于sa_flags=0的示例;这意味着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(f

我需要在我的控制台应用程序中处理SIGINT,我发现了许多关于sa_flags=0的示例;这意味着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的东西)中工作得很好,但在多线程中不行。请任何人帮助我-我已经一整天都在这个问题中挣扎了

终于找到了正确的解决方案。只有当此信号与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();
} 
std::可选trd;
std::互斥mtx;
无效整数处理程序(整数符号)
{
标准:锁紧装置lk(mtx);
if(trd&&std::this_thread::get_id()!=trd->get_id())
pthread_kill(trd->native_handle(),signum);
}
无效运行()
{
printf(“在getchar\n之前”);
自动c=getchar();
printf(“在getchar\n之后”);
}
int main()
{
//////设置SIGINT处理程序
结构sigsh;
sh.sa_handler=int_handler;
sigemptyset(和sh.sa_面具);
sh.sa_标志=0;
sigation(SIGINT,&sh,NULL);
返回0;
//////设置控制台
termios_prev{0};
//获取旧的终端i/o设置
tcgetattr(0和上一个);
//使新设置与旧设置相同
自动电流=_prev;
//禁用缓冲i/o
current.c_lflag&=~ICANON;
//设置无回声模式
current.c_lflag&=~ ECHO;
//现在就使用这些新的终端i/o设置
tcsetattr(0、TCSANOW和电流);
{
标准:锁紧装置lk(mtx);
训练部署和运行;
}
trd->join();
} 

当进程接收到信号时,可以将其定向到未阻止它的任何线程。因此,如果您想确保信号中断了
getchar()
,那么您必须确保通过在所有其他线程中阻塞信号来将信号传递到其线程。我的应用程序非常大(只是测试代码),所以我不知道我的应用程序的所有线程,线程可以由插件创建,或在其他用户代码中或在第三个LIB中。所以我不能使用这个解决方案……没有其他解决方案,@fsmoke。如果您想依靠使用信号来中断系统调用,那么必须采取适当的措施来确保将信号传递到运行该系统调用的线程。如果您不能确保这一点,那么您需要一种完全不同的方法。“如果您想依靠使用信号来中断系统调用”,很抱歉,但我不知道其他中断getchar的方法。。也许还有另一种方法……没有信号,你的回答中没有任何东西与我说的相矛盾,@fsmoke。您已经放弃了由击键生成的SIGINT,该SIGINT必须传递给任何特定线程,因此您的方法不满足我前面的评论中所表达的条件,并且
pthread_kill
将信号定向到特定线程,而不是整个进程。欢迎你朝正确的方向轻推。