c - 如何在管道的文件描述符上的线程 block 中进行 read() ?

标签 c pthreads pipe file-descriptor

我正在尝试如何在C语言中的线程和主函数之间进行通信 以下代码中有一个我不理解的行为:

#include <pthread.h>

#include <string.h>
#include <stdio.h>
#include <unistd.h>

void* output(void* pipe1);

int main(int argc, const char *argv[])
{
    pthread_t   tid0;
    int         pipe1[2];
    char        buffer[200];

// Creating the pipe
    pipe(pipe1);
// Creating the thread and passing the pipe as argument
    pthread_create(&tid0, NULL, output, &pipe1);
// Input from user
    scanf("%s", buffer);
// Writing to the pipe
    write(pipe1[1], buffer, strlen(buffer));
    return 0;
}

void* output(void* pipe1) {
     char buffer[200];

// Reading the pipe and print the buffer
     read(((int*)pipe1)[0], buffer, strlen(buffer));
     printf("thread say: %s\n", buffer);
     pthread_exit(NULL);
}

为什么读取函数不会在管道的文件描述符上阻塞?

也许我应该关闭管道的末端,但由于它们共享相同的内存空间,因此当我调用 read 或 write 时会返回错误“错误文件描述符”。

如果管道确实是一个糟糕的解决方案,也许你可以指导我使用其他方法(如果有一个例子,那就太棒了!:))

非常感谢!

编辑:解决方案

非常感谢您的回答,这里的代码具有预期的行为

#include <pthread.h>

#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

void* output(void* pipe1);

int main(int argc, const char *argv[])
{
    pthread_t   tid0;
    int         pipe1[2];
    char        buffer[200];

// Creating the pipe
    pipe(pipe1);
// Creating the thread and passing the pipe as argument
    pthread_create(&tid0, NULL, output, &pipe1);

// Input from user
    scanf("%s", buffer);
// Writing to the pipe
    if (write(pipe1[1], buffer, strlen(buffer)) < 0) {
        perror("write");
        exit(1);
    }
    // join so the main "wait" for the thread
    pthread_join(tid0, NULL);
    return 0;
}


void* output(void* pipe1) {
    char        buffer[200];
    int         nread;

// Reading the pipe and print the buffer
    nread = read(((int*)pipe1)[0], buffer, sizeof buffer - 1);
    if (nread < 0) {
        fprintf(stderr, "ERROR\n");
        perror("read");
        exit(1);
    }
    buffer[nread] = '\0';
    fprintf(stderr, "thread say: %s\n", buffer);
    pthread_exit(NULL);
}

最佳答案

char buffer[200];
read(((int*)pipe1)[0], buffer, strlen(buffer));

您正在对未初始化的缓冲区调用strlen。这会导致你的程序崩溃。相反,您很幸运,它所做的只是告诉 read 读取零字节,因此 read 返回而不执行任何操作。

你真正想要的是

ssize_t nread = read(((int *)pipe1)[0], buffer, sizeof buffer - 1);
if (nread < 0) {
    perror("read");
    return 0;
}
buffer[nread] = '\0';

read 想要知道的是您要给它读入多少空间,而不是该字符串中可能存在或尚未存在的任何字符串的长度空间。这是 sizeof buffer 减一,这样我们总是有空间来添加字符串终止符。

写入时使用strlen是正确的,因为你只想写入实际的字符串,而不是任何可能超出字符串末尾的垃圾;但是 write 不会将字符串终止符写入管道,因此 read 不会读取,因此您必须通过以下方式添加它:手。当然,还要始终检查错误。

此外,请记住线程同时运行。即使修复了此错误后,当读取器线程调用 read 时,write 可能已经发生,如果还没有发生,它可能很快就会发生。如果您想观察读取线程在读取时实际阻塞,则需要在调用写入之前延迟。

关于c - 如何在管道的文件描述符上的线程 block 中进行 read() ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50309109/

相关文章:

c - C中图形的线性代数

python - 从 stdin 读取,同时消耗的内存不超过需要

c - 如何管道不同的进程? (C)

c - 打印更新的阵列板

c - 为什么代码不打印任何东西作为输出?

c - pthreads并行化错误结果

c++ - 静态内存中的STL结构 'Losing' 跨线程数据

powershell - 在 PowerShell 中连接到 ForEach-Object

c++ - 将 Arduino 库与 AVR-G++ 结合使用

c - pthread_cond_broadcast 不起作用?