取消getchar()

时间:2012-07-16 22:34:48

标签: c pthreads getchar

我有一个小程序,可以进行大量处理。通过按Enter键可以获得打印的进度。

我实现这个的方法是在主线程中完成处理,同时我有一个pthread不断循环getchar()以等待回车键。

问题在于我完成了处理。当发生这种情况时,主线程结束,但仍然等待输入被按下,因为getchar()正在阻塞。

如何“取消”getchar()?

5 个答案:

答案 0 :(得分:3)

我能想到的最便携的解决方案是:

  • 使用pipe()构建两个FD,一个是读者,另一个是作家。给读者你的read()循环;给作者以任何需要终止读者的人。
  • 使用读取线程中的select()来等待stdin和读取器管道的可读性。
  • 如果stdin变得可读,请读取一个字符,处理它,然后重新启动循环。
  • 如果阅读器管道变得可读,请将其关闭并终止循环。

现在,您所要做的就是关闭管道的另一端,这会将读取器线程从其select()中唤醒,然后终止。

传统方法涉及使用信号,但是这种基于管道的解决方案允许您检查stdin上的输入以及检查是否应该使用相同的轮询机制终止。


请注意,混合使用getchar()select()无效,因为getchar()会有效地使用fread(),而fread()执行的缓存可以即使有可用数据,也会导致select()阻止。请改用read()。这是我用来测试这种方法的示例程序。

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/select.h>

void * entry_point(void * p) {
    int readpipe = *(int *)p;
    fd_set rfds;

    char c;

    for (;;) {
        FD_ZERO(&rfds);
        FD_SET(STDIN_FILENO, &rfds);
        FD_SET(readpipe, &rfds);

        while (select(readpipe + 1, &rfds, NULL, NULL, NULL) == 0);

        if (FD_ISSET(readpipe, &rfds)) {
            close(readpipe);
            break;
        }

        if (FD_ISSET(STDIN_FILENO, &rfds)) {
            if (read(STDIN_FILENO, &c, sizeof(c)) > 0) {
                printf("Read: %d\n", c);
            }
        }
    }

    printf("Thread terminating\n");

    pthread_exit(NULL);
}

int main() {
    pthread_t thread;
    int r;
    int pipes[2];

    pipe(pipes);

    if (r = pthread_create(&thread, NULL, entry_point, &pipes[0])) {
        printf("Error: %d\n", r);
        return 1;
    }

    sleep(5);

    printf("Closing pipe and joining thread.\n");

    close(pipes[1]);
    pthread_join(thread, NULL);

    pthread_exit(NULL);
}

示例运行:

$ time ./test
1
Read: 49
Read: 10
2
Read: 50
Read: 10
3
Read: 51
Read: 10
4
Read: 52
Read: 10
5
Read: 53
Read: 10
Closing pipe and joining thread.
Thread terminating

real    0m5.004s
user    0m0.004s
sys     0m0.000s

答案 1 :(得分:0)

假设你想沿着这条路走,你可以使用pthread_kill来强制你的getchar线程退出。见Kill Thread in Pthread Library。同样,不是最好的编程实践。

答案 2 :(得分:0)

拥有共享变量怎么样?然后在每次getchar()返回后,它会获取一个锁,然后检查是否设置了这个共享变量。如果没有那么它会做你做的任何事情,如果它被设置然后线程退出。这样当main进入exit时它会抓取一个锁,设置变量,释放锁,打印到stdin,然后等待另一个线程退出。有点复杂,但它应该工作。 〜奔

答案 3 :(得分:-1)

使用printf()将字符写入stdin。

答案 4 :(得分:-1)

我非常喜欢关闭stdin的想法。这很好,可以工作。

以下关闭stdin:close(0); FCLOSE(标准输入);关闭(STDIN_FILENO);守护进程(0,0);

你也可以从主线程中向stdin写一个特殊的字符序列或者EOF,然后让它关闭。