Очереди сообщений: неверный дескриптор файла в уведомлении - PullRequest
0 голосов
/ 26 апреля 2020

Я создал таблицу дескрипторов файлов mq, и я пытаюсь передать числа из стандартного ввода одним из них.

Я использую уведомление, используя потоки, и когда число встречается в одном из очереди, которые он должен напечатать, например, «Число: 1 из очереди: 3».

Вот мой код:

#define _GNU_SOURCE
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <time.h>
#include <mqueue.h>

#define MAX_LENGTH 20

#define ERR(source) (\
    fprintf(stderr, "%s:%d\n", __FILE__, __LINE__),\
    perror(source),\
    kill(0, SIGKILL),\
    exit(EXIT_FAILURE)\
)

static void not_func(union sigval sv) {
    mqd_t queue;
    uint8_t number;
    unsigned msg_prio;

    queue = *((mqd_t*)sv.sival_ptr);

    static struct sigevent not;
    not.sigev_notify = SIGEV_THREAD;
    not.sigev_notify_function = not_func;
    not.sigev_value.sival_ptr = &queue;
    if(mq_notify(queue, &not)<0) ERR("mq_notify");

    for(;;) {
        if(mq_receive(queue, (char*)&number, 1, &msg_prio)<1) {
            if(errno == EAGAIN) break;
            else ERR("mq_receive");

            printf("Number: %d from queue: %d", number, msg_prio);
        }
    }
}

void get_queue_name(int nr, char *str) {
    snprintf(str, MAX_LENGTH, "/queue%d", nr);
}

mqd_t create_message_queue(int nr) {
    mqd_t queue;
    char name[MAX_LENGTH] = "";
    get_queue_name(nr, name);

    struct mq_attr attr;
    attr.mq_maxmsg = 10;
    attr.mq_msgsize = 1;

    if((queue = TEMP_FAILURE_RETRY(mq_open(name, O_RDWR|O_NONBLOCK|O_CREAT, 0600, &attr))) == (mqd_t)-1) ERR("mq open in");

    static struct sigevent not;
    not.sigev_notify = SIGEV_THREAD;
    not.sigev_notify_function = not_func;
    not.sigev_value.sival_ptr = &queue;
    if(mq_notify(queue, &not)<0) ERR("mq_notify");

    return queue;
}

void delete_message_queue(mqd_t queue, int nr) {
    char name[MAX_LENGTH] = "";
    get_queue_name(nr, name);

    mq_close(queue);
    if(mq_unlink(name)) ERR("mq_unlink");
}

void usage(void) {
    fprintf(stderr, "USAGE: mqueue n\n");
    fprintf(stderr, "100 > n > 0 - number of children\n");
    exit(EXIT_FAILURE);
}

int main(int argc, char **argv) {
    int n, i;
    char strnumber[MAX_LENGTH]; 
    int number;

    mqd_t *queues;

    srand(time(NULL));

    if(argc != 2) usage();
    n = atoi(argv[1]);
    if(n<=0 || n>=100) usage();

    queues = (mqd_t*)malloc(sizeof(mqd_t) * n);
    if(queues == NULL) ERR("malloc");

    for(i = 0; i < n; i++) {
        queues[i] = create_message_queue(i+1);
    }

    while(fgets(strnumber, MAX_LENGTH, stdin)!=NULL) {
        number = (uint8_t)atoi(strnumber);
        if(number<=0) continue;

        int randomQueue = rand()%n;
        if(TEMP_FAILURE_RETRY(mq_send(queues[randomQueue], (const char *)&number, 1, (unsigned)randomQueue))) ERR("mq_send");
    }

    for(i = 0; i < n; i++) {
        delete_message_queue(queues[i], i+1);
    }

    free(queues);

    return EXIT_SUCCESS;
}

Когда я выполняю свой код, ничего не происходит:

nothing happens

или у меня такая ошибка:

bad file descriptor

1 Ответ

0 голосов
/ 26 апреля 2020

Вы передаете указатель на queue (который является локальной переменной) потоку (через not.sigev_value.sival_ptr), который запускается после того, как эта переменная выходит из области видимости. Таким образом, он получает висячий указатель.

Либо передайте дескриптор по значению (если он умещается в sigval; он должен), либо сохраните его в куче (с new / malloc) и передайте этот указатель.

...