消息队列。 msgsnd:参数无效

时间:2017-03-31 06:43:05

标签: c linux multithreading fork

任务是: 查找指定的数字间隔内的所有素数,并将其划分为多个范围。 每个范围都在生成的过程中处理。 好吧,我真的想成功。但是出了点问题。无法理解我的错误。 代码:

#include <stdio.h>
#include <sys/msg.h>
#include <stdlib.h>
#include <unistd.h>
#include <wait.h>
#include <stdbool.h>

#define MAX_SEND_SIZE 50

#define PROCESS_NUMBER 5

struct mymsgbuf {
    long mtype;
    int marray[MAX_SEND_SIZE];
};
typedef struct mymsgbuf type_mymsgbuf;

int msgqid, rc;

void send_message(int qid, type_mymsgbuf* qbuf, long type, int* text, int numbers_per_process) {
    int i;
    int length = sizeof(struct mymsgbuf) - sizeof(long);
    qbuf->mtype = type;
    for (i = 0; i < numbers_per_process; i++) {
        qbuf->marray[i] = text[i];
    }
    if ((msgsnd(qid, (struct msgbuf*)qbuf, (size_t) length, 0)) == -1) {
        perror("msgsnd");
        exit(1);
    }
}

void read_message(int qid, type_mymsgbuf* qbuf, long type, int numbers_per_process) {
    int length = sizeof(struct mymsgbuf) - sizeof(long);
    qbuf->mtype = type;
    msgrcv(qid, (struct msgbuf*)qbuf, (size_t)length, type, 0);
    for (int i = 0; i < numbers_per_process && qbuf->marray[i] != 0; i++) {
        printf("%d\n", qbuf->marray[i]);
    }
}

bool isprime (int a) {
    if(a == 1) {
        return false;
    }
    for (int i = 2; i*i < a; ++i) {
        if ((a % i) == 0) {
            return false;
        }
    }
    return true;
}

int* find_primes_part (int a, int b) {
    int j = 0;
    int* primes = (int*)malloc(sizeof(int)*(b-a));
    for (int k = 0; k < (b-a); ++k) {
        primes[k] = 0;
    }
    for (int i = a; i < b; ++i) {
        if(isprime(i)) {
            primes[j] = i;
            printf("%d\n TEST", primes[j]);
            j++;
        }
    }
    return primes;
}

int find_primes(int a, int b) {
    int status, stat;
    pid_t pid[PROCESS_NUMBER];
    key_t key;
    int qtype = 1;
    type_mymsgbuf qbuf;

    int numbers_per_process = (b-a)/PROCESS_NUMBER;
    if ((key = ftok(".", 'm')) < 0) {
        perror("ftok");
        exit(1);
    }
    if((msgqid = msgget(key, IPC_CREAT|0660)) == -1) {
        perror("msgget");
        exit(1);
    }

    for (int i = 0; i < PROCESS_NUMBER; i++) {
        pid[i] = fork();

        if (-1 == pid[i]) {
            perror("fork");
            exit(1);
        }
        else if (0 == pid[i]) {
            int* part_primes = find_primes_part(a + numbers_per_process*i, a + numbers_per_process*(i+1));
            send_message(msgqid, (type_mymsgbuf*)&qbuf, qtype, part_primes, numbers_per_process);
        }
    }
    for (int j = 0; j < PROCESS_NUMBER; ++j) {
        status = waitpid(pid[j], &stat, 0);
        if (pid[j] == status) {
            if (WEXITSTATUS(stat) != 0) {
                perror("process failed: ");
                exit(1);
            }
        }
    }
    for (int i = 0; i < PROCESS_NUMBER; ++i) {
        read_message(msgqid, &qbuf, qtype, numbers_per_process);
    }

    if ((rc = msgctl(msgqid, IPC_RMID, NULL)) < 0) {
        perror("msgctl");
        return 1;
    }
    return 0;
}

int main() {
    find_primes(10, 200);
    return 0;
}

输出非常错误,并且每隔一段时间都不同。 它类似于:

181
191
193
197
199
163
167
169msgsnd: Invalid argument

173
179
181
191
193
197
msgctl: Invalid argument

主要问题是这2个错误

msgsnd: Invalid argument
msgctl: Invalid argument

如何消除它?

2 个答案:

答案 0 :(得分:2)

我怀疑过早删除了邮件队列。

问题可能是每个进程(包括子进程)都执行清理代码。只有父级应该运行清理代码。

我认为您在调用exit(0);后立即错过了客户特定代码中的send_message()或{{1}}。

答案 1 :(得分:1)

您应该按照以下方式完成您的子进程:

else if (0 == pid[i]) {
    // I'm child
    int* part_primes = find_primes_part(a + numbers_per_process*i, a + numbers_per_process*(i+1));
    send_message(msgqid, (type_mymsgbuf*)&qbuf, qtype, part_primes, numbers_per_process);
    return 0; // --> exit from the child process
}

/* Both parent and child come here if you do not return from child*/