【问题标题】:Error with redirecting input from file to C multiprocessed program将输入从文件重定向到 C 多处理程序时出错
【发布时间】:2021-09-25 04:51:59
【问题描述】:

我从文件input1.txtinput2.txt 在shell 脚本的帮助下输入到程序中,我希望在文件a.txtb.txt 中包含这些文件的内容,但在一个文件中可以,但在另一个文件中像这样的垃圾-489663824 -489663824 -489663824 -489663824 -489663824,谁知道这是怎么回事?

C 代码:

#include <stdio.h>
#include <stdlib.h>
// for multiprocessing
#include <unistd.h>
#include <sys/wait.h>
// for shared mutex
#include <pthread.h>
#include <sys/mman.h>

pthread_mutex_t mutex;
pthread_mutexattr_t mutexattr;

void write_to_file(const char *filename, const int n)
{
    FILE *file = fopen(filename, "w");
    int value;

    printf("fill file with %d values: ", n);
    for (int i = 0; i < n; ++i) {
        scanf("%d", &value);
        fprintf(file, "%d ", value);
    }
    fprintf(file, "\n");
    printf("\n");

    fclose(file);
}

void task(const char *filename, pthread_mutex_t *shared_mutex)
{
    pthread_mutex_lock(shared_mutex);
    write_to_file(filename, 5);
    pthread_mutex_unlock(shared_mutex);
}

int main()
{
    // mutex routine
    pthread_mutex_t *shared_mutex;
    pthread_mutexattr_init(&mutexattr);
    pthread_mutexattr_setpshared(&mutexattr, PTHREAD_PROCESS_SHARED);
    shared_mutex = (pthread_mutex_t *)mmap(NULL, sizeof(mutex), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
    pthread_mutex_init(shared_mutex, &mutexattr);
    // mutex routine

    int pid = fork();
    if (pid == -1) {
        perror("fork() failed\n");
        exit(1);
    }
    if (pid == 0) {
        task("b.txt", shared_mutex);
        return 0;
    } else {
        task("a.txt", shared_mutex);
        wait(NULL);
    }

    // mutex routine
    pthread_mutexattr_destroy(&mutexattr);
    pthread_mutex_destroy(&mutex);
    munmap(shared_mutex, sizeof(mutex));
    // mutex routine

    return 0;
}

shell脚本:

echo "9 8 7 6 5 " >> input1.txt
echo "4 3 2 1 0 " >> input2.txt

cat "input1.txt" "input2.txt" | ./test

cmp_files()
{
    if cmp --silent -- "$1" "$2"; 
    then
        echo "write_to_file: ok"
    else
        echo "write_to_file: not ok"
    fi
}

cmp_files "input1.txt" "a.txt"
cmp_files "input2.txt" "b.txt"

rm input1.txt
rm input2.txt

【问题讨论】:

  • 好像scanf 失败了。可能所有文件数据都进入了另一个进程的缓冲区。
  • @user253751 我试过刷新它,但没有帮助

标签: c linux shell multiprocessing


【解决方案1】:

因为您正在将cat 的输出流水线化到您的程序,其中一个进程将通过提前读取来缓存输入,并且对于fork 子级或父级(取决于谁先获取互斥锁)。

在分叉之前使用setvbuf()(手动here)禁用stdin 的流缓冲。在从stdin 读取任何内容之前,将此调用添加到您的main() 之上,您的应用程序将正常工作:

int main()
{
    setvbuf(stdin, NULL, _IONBF, 0);
    [...]

一个进程(父进程或子进程,无论谁先到达那里)正在提前读取并将stdin 的内容存储到缓冲区中。另一个进程在运行scanf() 时将获得EOF,因为stdin 没有可供读取的内容,因此您在b.txt 中看到的“垃圾”值。这些是value 变量的重复打印,具有相同的未初始化值,因为scanfEOF 退出并且从未修改过它。

在使用setvbuf() 修补您的代码之前,您可以通过验证scanf() 返回的内容来检查这是否属实:

       int ret = scanf("%d", &value);
        if (ret < 0) {
            if (errno == 0) {
                printf("scanf failed: EOF\n");
                break;
            } else {
                printf("scanf failed, errno %d\n", errno);
            }
        }

您将看到无法从标准输入读取的进程正在打印scanf failed: EOF

【讨论】:

  • 这是一种合理的方法,但完全避免缓冲读取也可能是件好事。通过使用read 一次读取一个字符来实现这一点将具有教育意义。
  • 您能否解释或发送有关此问题的材料:为什么当我们使用 type 命令进行 scanf 时,进程阻塞并等待 scanf 返回?在这种情况下,它永远不会阻塞,并继续获得“垃圾”值?
  • 这是因为在第一种情况下,您的程序的标准输入是由终端通过管道传输的,而在第二种情况下,您的stdincat 程序的管道输出。后者在打印内容结束时发送EOF(关闭管道)并立即发送所有内容,从而允许您的程序在运行scanf时向前读取。除非您明确要求,否则终端不会发送EOF(例如,通过按CTRL-D,具体取决于您的终端)。此外,它不会提前发送输入数据,它只发送您输入的内容,不允许正在运行的程序提前读取并缓存输入。
  • @lidar 感谢您的提问。我已经更新了答案以明确说明在流水线 cat 的输出时会发生这种情况。
猜你喜欢
  • 1970-01-01
  • 2020-12-13
  • 1970-01-01
  • 2015-06-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-21
  • 2020-10-24
相关资源
最近更新 更多