简体   繁体   中英

Message queues: Bad file descriptor in notification

I've created a table of mq file descriptors and I'm trying to pass numbers from stdin by one of them.

I'm using notification using threads and when a number occures in one of the queues it should print for example "Number: 1 from queue: 3".

Here's my code:

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

When I execute my code nothing happens:

什么都没发生

or I have such an error:

错误的文件描述符

You pass a pointer to queue (which is a local variable) to the thread (via not.sigev_value.sival_ptr ) which runs after that variable goes out of scope. So it gets a dangling pointer.

Either pass the descriptor by value (if it fits in sigval ; it should), or store it on the heap (with new / malloc ) and pass that pointer.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM