Как сделать read () в блоке потока на дескриптор файла канала? - PullRequest
0 голосов
/ 12 мая 2018

Я экспериментирую с тем, как установить связь между потоком и основной функцией в 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);
}

Почему функция чтения не 't блокировать дескриптор файла канала?

Может быть, мне следует закрыть конец канала, но, поскольку они совместно используют одно и то же пространство памяти, при вызове read или write возвращается ошибка «bad file descriptor».

Может быть, вы можете привести меня к другим методам, если труба действительно плохое решение (на примере это будет удивительно! :))

Большое спасибо!

РЕДАКТИРОВАТЬ: РЕШЕНИЕ

Большое спасибо за ваш ответ. Вот код с ожидаемым поведением

#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);
}

1 Ответ

0 голосов
/ 12 мая 2018
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 не читает единицу, поэтому вы должны добавить его вручную.И, конечно же, всегда проверяйте наличие ошибок.

Кроме того, имейте в виду, что потоки одновременно запускают .Даже после исправления этой ошибки, write может уже произойти к тому моменту, когда поток чтения вызывает read, а если нет, то, вероятно, это произойдет очень скоро.Если вы хотите наблюдать за тем, как поток чтения действительно блокируется в read, вам необходимо отложить вызов до 1030 *.

...