2014-11-01 69 views
1

我試圖通過推送和彈出字符進出隊列來編寫生產者消費者問題。有兩個主要文件,producer.c和consumer.c。它們都有在開始時初始化的共享內存空間。生產者將首先運行,並將初始化共享指針中的變量(static struct shared * sharedptr)。其中之一是一個隊列(結構隊列*緩衝區)。C - 處理共享內存時出現分段錯誤

生產者從文件中讀取字符並逐個放入(推送)一個隊列,然後消費者逐個讀取,打印並從隊列中取出字符(彈出)。

問題是:生產者在獲取隊列指針(memptr - > buffer)和推入字符方面沒有任何問題。但是,生產者不能訪問隊列,儘管它應該有相同的指向隊列的指針。

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

當我和這個測試的分割發生故障:

它檢查是否緩衝區爲NULL,當我用這個if語句進行測試時,正確打印

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

回答

1

這裏有一個問題:你調用shmat與放慢參數shmaddr零(NULL)。這告訴系統將共享內存段映射到它想要的任何地址。 無法保證映射地址在兩個進程中都是相同的!如果在兩個進程中使用不同的基址,則由一個(生產者)寫入的指針不會對另一個(消費者)有效。

1

您不能像這樣在共享內存中使用指針(struct Queue *bufferFILE *file),因爲當您使用例如內存分配內存時,生產者中的malloc(),那麼只有該進程可以訪問來自該指針的數據。

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

欲瞭解更詳細的信息,你可以檢查在這個問題的答案:Pointers inside shared memory segment