[英]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 *buffer
和FILE *file
),因為在Producer中使用malloc()
分配內存時,只有該進程才能從該指針訪問數據。
您可以做的是為*buffer
和*file
創建兩個額外的共享內存,並將它們附加到*memptr
。 但是通常,指針並不是真的要在共享內存中使用。
有關更多詳細信息,您可以檢查以下問題的答案: 共享內存段中的指針 。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.