【问题标题】:Segmentation Fault in C producer/consumer using messagequeue使用消息队列的 C 生产者/消费者中的分段错误
【发布时间】:2017-10-27 22:42:10
【问题描述】:

我正在做一个使用 UNIX 消息队列作为单个生产者和三个消费者共享的数据结构来实现生产者/消费者问题的作业。我正在创建的程序应该创建一个子进程,而子进程将依次创建三个线程。父进程是生产者,三个线程是消费者。要生成的项目数 N 将通过命令行提供给程序。产生子进程后,父进程将进入 N 次迭代循环。在循环的每次迭代中,父级将执行以下操作:

1) 生成一个随机数,R,范围为 0-999。

2) 发送包含 R 的消息。

3) 将 R 添加到产生的所有值的运行总和中。

4) 显示字符串“Producerproduced a R”。

5) 使用 sleep(rand()%2) 让生产者休眠 0-1 秒。

N 次迭代完成后,显示字符串“Totalproduced = XXXX”(其中 XXXX 是所有 R 值的总和)并等待子进程终止。创建和销毁队列是父进程的责任。

子进程将创建三个消费者线程,0、1和2。每个线程将进入一个N/3迭代循环。在循环的每次迭代中,每个消费者线程都会执行以下操作:

1) 从队列中读取包含值 C 的消息。

2) 将 C 添加到每个消费者线程维护的运行总数中。

3) 显示字符串“Consumer thread Z consume a C”,其中 Z 是线程号 - 0,1 或 2。

4) 使用 sleep((rand()%3)+1) 使消费者线程休眠 1-3 秒

N/3 次迭代后显示字符串“消费者线程 Z = YYYY 消耗的总和”,其中 YYYY 是所有 N/3 个消耗值的总和。我在循环的最后一次迭代中收到分段错误,我是不知道为什么。有人可以帮我解决这个问题吗?

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <sys/msg.h>
#include <sys/wait.h>
#include <pthread.h>
#include <sys/sem.h>
#include <semaphore.h>

struct msgbuf {
    long mtype;
    int mnum;
};
int msqid;
unsigned long total;
pthread_mutex_t sem_id;

int init() {
    srand (time(NULL));
    msqid = msgget(IPC_PRIVATE, IPC_CREAT | 0600);
    if (msqid == -1) { perror("msgget"); return EXIT_FAILURE; }
    pthread_mutex_init(&sem_id, NULL);
    total = 0;
    return 0;
}

int producer() {
    int R = rand() % 999;
    struct msgbuf msg = {999, R};
    if(msgsnd(msqid, &msg, sizeof(msg.mnum) + 1, 0) == -1) { 
perror("msgsnd"); return -1; }
    total += R;
    return R;
}

void *consumer(int thread_num, int iteration) {
    struct msgbuf msg;
    int thread_total = 0;
    while(iteration--) {
        pthread_mutex_lock(&sem_id);
        if (msgrcv(msqid, &msg, sizeof(msg.mnum) + 1, 0, 0) == -1) 
perror("msgrcv");
        thread_total += msg.mnum;
        printf("Consumer thread %d consumed a %d\n", thread_num, msg.mnum);
        pthread_mutex_unlock(&sem_id);
    }
    printf("Total consumed by consumer thread %d = %d\n", thread_num, 
thread_total);
    sleep((rand()%3)+1);
}

int main(int argc, char *argv[]) {
    int N = argc > 1 ? atoi(argv[1]) : 10;
    if (init() != 0) return EXIT_FAILURE;

    for (int i=0;i<N;i++) {
        int R = producer();
        if(R == -1) return EXIT_FAILURE;
        printf("Producer produced a %d\n", R);
        sleep(rand()%2);
    }
    printf("Total produced = %lu\n", total);
    pthread_t thread_nums[3];
    for (int i=0; i<=4; i++) {
        int iteration = i == 0 ? N/3 + (N%3) : N/3;
        if(pthread_create(&thread_nums[i], NULL,
            consumer(i, iteration), NULL) != 0) {
                perror("pthread_create");
                return EXIT_FAILURE;
        }
    }
    for (int i=0;i<4;i++) pthread_join(thread_nums[i], NULL);
    return 0;
}

【问题讨论】:

  • 子进程在哪里?
  • 您对pthread_create 的调用不正确。您需要通过原型void* consumer(void* param); 向它传递一个函数。如果您想将多个项目传递给consumer(看起来像您这样做),您需要将它们放入struct 并传递它,然后将其从void* 转换回您的struct。做一些类似pthread_create(&amp;thread_nums[i], NULL, consumer, (void*)&amp;myStruct);pthreads的好信息在这里:computing.llnl.gov/tutorials/pthreads
  • 我认为您不需要使用互斥锁来保护msgrcv()。您不需要更新使用者中的任何全局变量,因此它不需要互斥体。

标签: c multithreading


【解决方案1】:

好的,所以在 main 函数中,thread_nums 有 3 个“槽”,其中循环进行时想要超过 5 个不同的“槽”。

另外,最后一个循环访问了一个不存在的“槽”

请记住,大小为 [3] 的数组只有三个位置。最后一项位于索引 2 (0,1,2),总共三个元素。

【讨论】:

    猜你喜欢
    • 2018-02-05
    • 1970-01-01
    • 2014-01-07
    • 1970-01-01
    • 2017-02-11
    • 1970-01-01
    • 1970-01-01
    • 2012-01-28
    • 1970-01-01
    相关资源
    最近更新 更多