我试图通过推送和弹出字符进出队列来编写生产者消费者问题。有两个主要文件,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;
}