c++ - 如果 I/O read() 处于阻塞阶段,如何使用 Ctrl+C 退出 C++ 程序?

标签 c++ multithreading io ros can-bus

我正在ROS环境下工作,并尝试在并行线程上读取CANBUS。我在主线程中初始化了 canbus,因为我想确保 CAN 电缆已连接。通过初始化,我的意思是 setsockopt()ioctl()bind() 来配置套接字。

void readCanbus(int soktId) {
    while(true)
        int nbytes = read(soktId, ...);
}

int main() {
    int soktId;
    someSocketSetupFn(soktId);

    std::thread t(readCanbus, soktId);

    t.join();
}

问题:如果没有传入 CAN 消息,则 read() 被阻止。 Ctrl+C 不会终止 C++11 程序。

如何使 read() 终止并终止整个程序?

Terminate thread c++11 blocked on read 这篇文章提出了 POSIX 的解决方案。我正在 ubuntu16.04 上工作。

最佳答案

如果您想模仿其他线程上的中断行为,这些线程必须允许中断,并且您的信号处理线程必须将信号传递给它们。考虑以下代码片段:

static volatile std::atomic<bool> quit;
static volatile std::deque<std::thread> all;
static volatile pthread_t main_thread;

void sigint_handler (int) {
    if (pthread_self() == main_thread) {
        write(2, "\rQuitting.\n", 11);
        quit = true;
        for (auto &t : all) pthread_kill(t.native_handle(), SIGINT);
    } else if (!quit) pthread_kill(main_thread, SIGINT);
}

退出是通过设置全局变量来传达的。线程将唤醒并检查该变量。唤醒线程就是访问该线程并向其发送信号。

如果工作线程在主线程之前拦截到 SIGINT,则会将其发送到主线程以启动正确的关闭序列。

为了允许被中断,线程可以调用siginterrupt()

void readCanbus(int s) {
    siginterrupt(SIGINT, 1);
    while(!quit) {
        char buf[256];
        int nbytes = read(s, buf, sizeof(buf));
    }
    write(2, "Quit.\n", 6);
}

我们定义了两种安装信号处理程序的方法,一种使用 signal,另一种使用 sigaction,但使用提供类似于 signal< 的语义的标志.

template <decltype(signal)>
void sighandler(int sig, sighandler_t handler) {
    signal(sig, handler);
}

template <decltype(sigaction)>
void sighandler(int sig, sighandler_t handler) {
    struct sigaction sa = {};
    sa.sa_handler = handler;
    sa.sa_flags = SA_RESTART;
    sigaction(sig, &sa, NULL);
}

主线程安装信号处理程序,初始化main_thread,并使用稍后需要关闭的工作线程填充容器。

int main () {
    int sp[2];
    main_thread = pthread_self();
    socketpair(AF_UNIX, SOCK_STREAM, 0, sp);
    all.push_back(std::thread(readCanbus, sp[0]));
    sighandler<sigaction>(SIGINT, sigint_handler);
    for (auto &t : all) t.join();
}

关于c++ - 如果 I/O read() 处于阻塞阶段,如何使用 Ctrl+C 退出 C++ 程序?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59413344/

相关文章:

c++ - 提取基类指针

c++ - 合并排序 C++ 1 参数 - vector

c# - 线程,流畅的 nhibernate 和保存数据陷入僵局

multithreading - CodeSite 类别和线程

java - 如何从线程取回数组值

java - 十六进制字符串到图像

c++ - 在 linux mint 上学习 c++(适用于 .net 开发人员)

c++ - 在 std::vector 中存储函数在 linux 上可以正常工作,但甚至不能在 windows 上编译

c++ - 在 Windows 的 C++ 控制台应用程序中重新定义 'pause' 行为

c - getchar() 在 C 中给出输出