簡體   English   中英

C-處理共享內存時出現分段錯誤

[英]C - Segmentation fault when dealing with shared memory

我正在嘗試通過將字符推入和彈出隊列來編程生產者消費者問題。 有兩個主要文件,producer.c和consumer.c。 他們兩個都有在開始時初始化的共享內存空間。 Producer將首先運行,並將在共享指針(靜態結構shared * sharedptr)中初始化變量。 其中之一是隊列(struct Queue * buffer)。

生產者從文件中讀取字符,然后一次將其放入(推入)隊列,而消費者則一次讀取,打印並從隊列中取出(彈出)字符。

問題是:生產者在獲取隊列指針(memptr->緩沖區)和推入字符方面沒有問題。但是,生產者無法訪問隊列,盡管它應該具有指向隊列的相同指針。

當我使用以下if語句測試緩沖區時,它會在檢查緩沖區是否為NULL時正確打印:

if(memptr -> buffer == NULL)
    printf("Buffer is empty.\n");
else printf("Buffer is not empty.\n");

當我對此進行測試時,就會發生細分錯誤:

if(memptr -> buffer == NULL)
    printf("Buffer is empty.\n");
else if (memptr -> buffer -> tail == NULL){
    printf("Tail is NULL. Something went wrong.\n");
    exit(1);
}

我認為它是在它接近尾巴的時候發生的。 它甚至不評估尾部是否為NULL; 它只是發送了段錯誤。 當我在common.c中測試所有與隊列相關的功能時(在下面提供),並沒有發生這種情況,而且生產者也可以正常運行。

指針發生了什么? 使用者可以訪問(struct shared *)的memptr中的其他變量,但不能訪問buffer-> tail。 這對我來說沒有任何意義。

我在Mac上編譯程序:

cc -c common.c

cc -o producer -Wall producer.c common.o

cc -o consumer -Wall consumer.c common.o

這是我所有的代碼:

COMMON.H:

#define MEMSIZE 200
#define BUFFSIZE 5
#define MAXCOUNT 10

struct shared {
    /* synchronization variables */
    int choosing[MAXCOUNT + 1];
    int ticket[MAXCOUNT + 1];
    /* queue variables */
    struct Queue *buffer;
    int endOfFile;
    int in;     //variable that keeps track of bytes coming in
    int out;    //variable that keeps track of bytes coming in
    int count;  //count variable for producers
    FILE *file;
};

struct Link {
    char value;
    struct Link *next;
    struct Link *prev;
} Link;

struct Queue {
    int size;
    struct Link *head;
    struct Link *tail;
} Queue;

void mutexInit(struct shared *memptr);
void getMutex(short pid);
void releaseMutex(short pid);
void firstInit();
int max(int array[], int maxIndex);

struct Queue *initQueue();
struct Queue *push(char ch, struct Queue *q);
struct Queue *pop(struct Queue *q);
void printQueue(struct Queue *q);
char getBuffer(struct Queue *q);

common.c中:

#include <stdio.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdlib.h>

#include <limits.h>

#include "common.h"

#define FALSE 0
#define TRUE 1

static struct shared *sharedptr;

void mutexInit(struct shared *memptr){
    sharedptr = memptr;
}

void firstInit(){
    //initialize all variables to initial state
    int i;

    for(i = 0; i < 11; i++) {
        sharedptr -> choosing[i] = 0;
        sharedptr -> ticket [i] = 0;
    }
    sharedptr -> buffer = initQueue();
    sharedptr -> endOfFile = FALSE;
    sharedptr -> in = 0;
    sharedptr -> out = 0;
    sharedptr -> count = 1;
    sharedptr -> file = fopen("/Users/BenjaminHsu/Documents/ELEC 377/lab3/Queue/lab3.txt", "r");
    if(sharedptr -> file == NULL){
        printf("Can't find file.\n");
            exit(0);
    }
}

void getMutex(short pid){
    // this should not return until it has mutual exclusion. 
    // Note that many versions of this will probobly be running at the same time.
    int j;

    sharedptr -> choosing[pid] = TRUE;
    sharedptr -> ticket[pid] = max(sharedptr -> ticket, sharedptr -> count + 1) + 1; 
    sharedptr -> choosing[pid] = FALSE;
    for (j = 0; j < sharedptr -> count + 1; j++){
        while(sharedptr -> choosing[j] == TRUE);
        while(sharedptr -> ticket[j] != FALSE && ((sharedptr -> ticket[j] <= sharedptr -> ticket[pid])     && j < pid));
    }
}

void releaseMutex(short pid){
    // set the mutex back to initial state so that somebody else can claim it
    sharedptr -> ticket[pid] = 0;
}

int max(int array[], int maxIndex){
    int max = array[0];
    int i;

    if(maxIndex == 0)
        return max;
    for(i = 1; i < maxIndex; i++){
        if(array[i] > max)
            max = array[i];
    }
    return max;
}    

struct Queue *initQueue(){
    struct Queue *q = (struct Queue*)malloc(sizeof(struct Queue));
    q -> size = 0;
    q -> head = NULL;
    q -> tail = NULL;
    return q;
}

struct Queue *push(char ch, struct Queue *q){
struct Link *temp = (struct Link*)malloc(sizeof(struct Link));

if(q != NULL) {
    temp -> value = ch;
    temp -> next = q -> head;
    temp -> prev = NULL;
    if(q -> size == 0){
        q -> head = temp;
        q -> tail = temp;
    } else {
        q -> head -> prev = temp;
        q -> head = temp;
    }
        q -> size++;
    } else {
        printf("The queue is NULL.\n");
        exit(0);
    }
    return q;
}

struct Queue *pop(struct Queue *q){
    if(q != NULL) {
        if(q -> size == 0){
            printf("nothing to pop.\n");
        } else if(q -> size == 1){
            q -> head = NULL;
            q -> tail = NULL;
        } else {
            q -> tail -> prev -> next = NULL;
            q -> tail = q -> tail -> prev;
        }
        q -> size--;
    } else {
        printf("The queue is NULL.\n");
        exit(0);
    }

    return q;
}

char getBuffer(struct Queue *q) {
    if(q -> tail != NULL)
        return (char)q -> tail -> value;
    else {
        printf("Buffer is empty.\n");
        exit(1);
    }
}

void printQueue(struct Queue *q){

    struct Link *temp;
    if(q != NULL){
        if(q -> size > 0){
            temp = q -> head;
            while(temp -> next != NULL){
                printf("%c->", temp -> value);
                temp = temp -> next;
            }
            printf("%c\n", temp -> value);
        } else 
            printf("Queue is NULL.\n");
    } else 
        printf("Queue is empty.\n");
}

producer.c

#include <stdio.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdlib.h>
#include <errno.h>

#include "common.h"

#define FALSE 0
#define TRUE 1

#define MYPID 1

int main (int argc, char *argv[]){

    // initialize the shared memory, load in the initial array's, spawn the worker
    // processes.
    key_t   key;
    struct shared *memptr;
    int shmid;
    int c;
    int pid;
    char ch;


    /*   Shared memory init     */
    key = ftok(".", 'S');
    if((shmid = shmget(key, MEMSIZE, IPC_CREAT|0666)) == -1 ){
        if( (shmid = shmget(key, MEMSIZE, 0)) == -1){
            printf("Error allocating shared memory. \n");
            exit(1);
        }
    }

    // now map the region..
    if((int)(memptr = (struct shared *) shmat(shmid, 0, 0)) == -1){
        printf("Couldn't map the memory into our process space.\n");
        exit(1);
    }

    mutexInit(memptr);

    //_______________________________
    memptr -> count = 0; //temp code to assume and test with one producer only
    //_______________________________


    if(memptr -> count == 0)
        firstInit(memptr);
    else if (memptr -> count >= MAXCOUNT) {
        printf("Exceed maximum limit for number of producers");
        exit(0);
    } else {
        memptr -> count++;
    }

    pid = memptr -> count;

    printf("pid:%d", pid);
    printf("eof: %d", memptr -> endOfFile);

    while(memptr -> endOfFile == FALSE) {
        if((memptr -> in - memptr -> out) < BUFFSIZE){
            ch = fgetc(memptr -> file); //read one character from the text file

            if(ch == EOF){
                memptr -> endOfFile = TRUE;
                break;
            }

            getMutex(pid); //wait for mutex
            memptr -> buffer = push(ch, memptr -> buffer); //write the character into the buffer
            printQueue(memptr -> buffer);
            releaseMutex(pid); 

            //______________________________________
            printf("%c", getBuffer(memptr -> buffer));  //a test to see if producer 
                                                        //can access buffer ->tail
            //______________________________________

            //increment the in variable
            memptr -> in++;
        }
    }

    memptr -> count--;

    return 0;
}

consumer.c:

#include <stdio.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdlib.h>
#include <errno.h>

#include "common.h"

#define FALSE 0
#define TRUE 1

#define MYPID 0

int main (int argc, char *argv[]){
    // initialize the shared memory, load in the initial array's, spawn the worker
    // processes.
    key_t   key;
    struct shared *memptr;
    int shmid;
    char ch;


    /*   Shared memory init     */
    key = ftok(".", 'S');
    if((shmid = shmget(key, MEMSIZE, IPC_CREAT|0666)) == -1 ){
        if( (shmid = shmget(key, MEMSIZE, 0)) == -1){
            printf("Error allocating shared memory. \n");
            exit(1);
        }
    }

    // now map the region..
    if((int)(memptr = (struct shared *) shmat(shmid, 0, 0)) == -1){
        printf("Couldn't map the memory into our process space.\n");
        exit(1);
    }

    mutexInit(memptr);

    do{
        if(memptr -> out < memptr -> in){ //compare the in and out to see if the buffer is empty
            if(memptr -> buffer == NULL)
                printf("Buffer is empty.\n");
            else if (memptr -> buffer -> tail == NULL){
                printf("Tail is NULL. Something went wrong.\n");
                exit(1);
            }

            ch = getBuffer(memptr -> buffer); //read a character from the buffer and print
            //wait for mutex
            getMutex(MYPID);
            printf("%c", memptr -> buffer -> tail -> value);
            memptr -> buffer = pop(memptr -> buffer);
            releaseMutex(MYPID);
            //release mutex

            memptr -> out++;
        }
    } while((memptr -> endOfFile == FALSE) || (memptr -> count != 0));

    return 0;
}

這是一個問題:您正在使用參數shmaddr零( NULL )調用shmat 這告訴系統將共享內存段映射到所需的任何地址。 不能保證兩個過程中映射的地址都相同! 如果在兩個進程中使用了不同的基址,則由一個(生產者)寫入的指針將對另一個(消費者)無效。

不能像在共享內存中那樣使用指針( struct Queue *bufferFILE *file ),因為在Producer中使用malloc()分配內存時,只有該進程才能從該指針訪問數據。

您可以做的是為*buffer*file創建兩個額外的共享內存,並將它們附加到*memptr 但是通常,指針並不是真的要在共享內存中使用。

有關更多詳細信息,您可以檢查以下問題的答案: 共享內存段中的指針

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM