c - 优雅地退出多线程进程

标签 c pthreads semaphore

我正在运行一个多线程 C 程序(进程?),利用信号量和 pthreads。线程持续交互、阻塞、唤醒并在标准输出上打印提示,无需任何人为干预。我希望能够通过按类似键盘字符来退出此进程(在打印消息并放下所有线程后优雅地退出,而不是通过粗略的 CTRL+C SIGINT) #.

我可以通过哪些选项来获取用户的此类输入?

我可以提供哪些更多相关信息来帮助解决此问题?

编辑: 你所有的答案听起来都很有趣,但我的主要问题仍然存在。当我不知道当前正在执行哪个线程时,如何获取用户输入?此外,如果通过 SIGINT 发出信号,则使用 sem_wait() 进行的信号量阻塞会中断,这可能会导致死锁。

最佳答案

从线程读取标准输入没有区别,除非有多个线程尝试同时读取它。不过,很可能您的线程并不总是调用函数来读取标准输入。

如果您经常需要读取用户的输入,您可能希望有一个线程只读取此输入,然后根据此输入设置标志或将事件发布到其他线程。

如果终止字符是您唯一想要的,或者如果这只是用于调试,那么您可能想做的是偶尔轮询标准输入上的新数据。您可以通过将标准输入设置为非阻塞并尝试偶尔读取它来做到这一点。如果读取返回 0 个读取字符,则表示没有按下任何键。但这种方法存在一些问题。在将底层文件描述符(int)设置为非阻塞后,我从未在 FILE * 上使用过 stdio.h 函数,但怀疑它们可能表现得很奇怪。您可以避免使用 stdio 函数并使用 read 来避免这种情况。我曾经读到过一个问题,如果您 fork 并执行一个有权访问该文件描述符版本的新程序,则另一个进程可能会更改 block /非 block 标志。我不确定这是否是所有系统上的问题。可以通过“fcntl”调用来设置或清除非阻塞模式。

但是您可以使用具有非常小的超时 (0) 的轮询函数之一来查看是否有数据准备就绪。 poll 系统调用可能是最简单的,但还有 select。各种操作系统还有其他轮询功能。

#include <poll.h>

...
/* return 0 if no data is available on stdin.
        > 0 if there is data ready
        < 0 if there is an error
*/
int poll_stdin(void) {
    struct pollfd pfd = { .fd = 0, .events = POLLIN };

    /* Since we only ask for POLLIN we assume that that was the only thing that
     * the kernel would have put in pfd.revents */
    return = poll(&pfd, 1, 0);
}

你可以在你的一个线程中调用这个函数,直到它返回 0,你就可以继续运行。当它返回正数时,您需要从 stdin 读取一个字符来查看它是什么。请注意,如果您在其他地方的 stdin 上使用 stdio 函数,实际上可能已经在新字符前面缓冲了其他字符。 poll 告诉您操作系统为您提供了一些新东西,而不是 C 的 stdio 拥有的东西。

如果您经常从其他线程中的标准输入读取内容,那么事情就会变得困惑。我假设您没有这样做(因为如果您这样做并且它工作正常,您可能不会问这个问题)。

关于c - 优雅地退出多线程进程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3997343/

相关文章:

c - 双参数数组排序

c - 彩票计划问题

c - 为什么这个 C 程序不能编译?错误 : undefined reference to `i2c_smbus_read_byte_data'

c - 使用内存泄漏的 pthread

android - 为什么我的 c 套接字死了?

c - 当尝试实现字符串数组时我做错了什么?

我可以使用单个 "pthread_mutexattr_t"属性来初始化两个不同的互斥量吗?

Java - 如何修改信号量实现以使其公平

c# - 多线程:限制并发线程数

semaphore - 了解信号量