fifo linux - функция write () завершает программу внезапно - PullRequest
0 голосов
/ 11 января 2019

Я реализую канал в C, где несколько программ-производителей (в моем случае 9) записывают данные в одну программу-потребитель.

Проблема в том, что некоторые производители (иногда один или два) внезапно завершают работу программы при вызове функции write ().

Код прост, вот код производителя:

#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <poll.h>

#define MSG_SIZE_BYTES 4

void send(unsigned int * msg){

    int fd, msg_size;
    int r;
    char buffer [5];
    char myfifo[50] = "/tmp/myfifo";

    fd = open(myfifo, O_WRONLY);

    if(fd == -1){
        perror("error open SEND to fifo");
    }

    r = write(fd, msg, MSG_SIZE_BYTES);

    if(r == -1){
        perror("error writing to fifo");
     }

    close(fd);
    printf("Message send\n");
}

int main(int argc, char *argv[]){
    int cluster_id = atoi(argv[1]);
    unsigned int msg[1];
    msg[0] = cluster_id;

    while(1){
        printf("Press a key to continue...\n");
        getchar();
        send(msg);
    }
}

А вот и код потребителя

#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <poll.h>

#define MSG_SIZE_BYTES 4

int receive(unsigned int * received_msg){
    int fd, msg_size;
    int ret_code;
    char buffer [5];
    char myfifo[50] = "/tmp/myfifo";

    fd = open(myfifo, O_RDONLY);

    if(fd == -1) 
       perror("error open RECV to fifo");

    ret_code = read(fd, received_msg, MSG_SIZE_BYTES);

    close(fd);

    if (ret_code == -1){
        printf("\nERROR\n");    
        return 0;
    }

    return 1;
}

void main(){

    mkfifo("/tmp/myfifo", 0666);

    unsigned int msg[1];
    while(1){
       receive(msg);
       printf("receive msg from id %d\n", msg[0]);

    }
}

Я собираю производителей и потребителей с помощью следующей команды: gcc -o my_progam my_program.c

Чтобы воспроизвести проблему, вам нужно открыть 9 терминалов для запуска каждого производителя и 1 терминал для запуска потребителя. Выполнить потребитель: ./consumer

Выполнить производителя во всех терминалах одновременно, передавая каждому выполнению связанный идентификатор, передаваемый командной строкой. Пример: ./producer 0, ./producer 1.

После того, как производитель отправит сообщения несколько раз (в среднем по 10), один произвольный производитель внезапно остановит его выполнение, показывая проблему.

На следующем рисунке изображено исполнение: Терминалы готовы к выполнению

На следующем рисунке изображена ошибка идентификатора производителя 3 Ошибка производителя 3

Заранее спасибо

Ответы [ 2 ]

0 голосов
/ 11 января 2019

Проблема решена:

Проблема в том, что я открывал и закрывал FIFO в каждом сообщении, создавая Сломанный канал при некоторых попытках записи. Удаление close () и вставка функции open () для ОБА-производителя и потребителя в начале кода вместо цикла внутри цикла решили проблему.

Вот код производителя с исправленной ошибкой:

#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <poll.h>

#define MSG_SIZE_BYTES 4

int my_fd;

void send(unsigned int * msg){

    int fd, msg_size;
    int r;
    char buffer [5];
    char myfifo[50] = "/tmp/myfifo"

    if(fd == -1){
        perror("error open SEND to fifo");
    }

    r = write(my_fd, msg, MSG_SIZE_BYTES);

    if(r == -1){
        perror("error writing to fifo");
     }

    //close(fd);
    printf("Message send\n");
}

int main(int argc, char *argv[]){
    int cluster_id = atoi(argv[1]);
    unsigned int msg[1];
    msg[0] = cluster_id;

    my_fd = open("/tmp/myfifo", O_WRONLY);

    while(1){
        printf("Press a key to continue...\n");
        getchar();
        send(msg);
    }
}

А вот код потребителя:

#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <poll.h>

#define MSG_SIZE_BYTES 4

int my_fd;

int receive(unsigned int * received_msg){
    int fd, msg_size;
    int ret_code;
    char buffer [5];
    char myfifo[50] = "/tmp/myfifo";

    if(fd == -1) 
       perror("error open RECV to fifo");

    ret_code = read(my_fd, received_msg, MSG_SIZE_BYTES);

    //close(fd);

    if (ret_code == -1){
        printf("\nERROR\n");    
        return 0;
    }

    return 1;
}

void main(){

    mkfifo("/tmp/myfifo", 0666);
    my_fd = open("/tmp/myfifo", O_RDONLY);

    unsigned int msg[1];

    while(1){
       receive(msg);
       printf("receive msg from id %d\n", msg[0]);

    }
}

Спасибо всем !!

0 голосов
/ 11 января 2019

Похоже, что программа-потребитель закрывает конец чтения канала после чтения данных:

fd = open(myfifo, O_RDONLY);

if(fd == -1){
     perror("error open RECV to fifo");
}
ret_code = read(fd, received_msg, MSG_SIZE_BYTES);

close(fd);

Все другие программы записи, которые в настоящее время пытаются write() данные (т.е. заблокированы в write() -системном вызове), теперь получают SIGPIPE, что приводит к завершению программы (если не указана другая обработка сигналов).

Ваша потребительская программа может не закрыть файловый дескриптор, пока пишут производители. Просто прочитайте следующий документ без закрытия.

...