2014-11-01 88 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