我试图通过在队列中推送和弹出字符来解决生产者和消费者的问题。有两个主文件producer.c和consumer.c。它们都在开始时初始化了共享内存空间。Producer将首先运行,并初始化共享指针(static struct shared*sharedptr)中的变量。其中之一是队列(struct queue*buffer)。
生产者从文件中读取字符,然后一次一个地放入(推送)队列,而消费者则一次一个地从队列中读取、打印和取出字符(pop)。
问题是:producer在获取队列指针(memptr->buffer)和推入字符方面没有问题。但是,生产者不能访问队列,尽管它应该具有指向该队列的相同指针。
当我使用以下if语句进行测试时,当检查缓冲区是否为空时,它将正确打印:
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);
}
我想它是在接近尾巴的时候发生的。它甚至不评估尾部是否为空;它只是发送segfault。当我使用common.c中所有与队列相关的函数(如下所示)进行测试时,并没有发生这种情况,而且producer运行良好。
指针怎么了?使用者可以访问(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
这是我所有的密码:
普通.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);
通用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");
}
制作人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;
}
消费者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;
}
最佳答案
这里有一个问题:您使用参数shmat
0(shmaddr
)调用NULL
。这告诉系统在它想要的任何地址映射共享内存段。无法保证映射的地址在两个进程中都是相同的!如果两个进程中使用不同的基址,则一个(生产者)编写的指针对另一个(消费者)无效。