使用文件描述符使用mmap共享结构数组

时间:2016-05-02 23:29:19

标签: c struct linked-list mmap

我正在尝试使用链表创建一个结构数组,用于写入并在mmap中读取它们。我在尝试读取数组数据时遇到了分段错误。

我确信这个问题与我使用指针的方式有关,因为我使用的是不同的结构。

编写代码:

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>

struct dogType
  {
    char nombre[32];
    int edad;
    char raza[16];
    int estatura;
    float peso;
    char sexo;
  };

struct dogType *dog;

struct test_struct
{
    struct dogType dog;
    struct test_struct *next;
};

struct node
{
    struct test_struct *head;
    struct test_struct *curr;
};

struct node nodes[10];
struct node *map;

int i;
long counter = 0;

struct test_struct* add_to_list(struct dogType *pet, bool add_to_end, int hashnumber);

void ini(void)
{

    strcpy(dog->nombre, "");
           dog->edad = 0;
           strcpy(dog->raza, "");
           dog->estatura = 0;
           dog->peso = 0;
           dog->sexo = ' ';

    for(i = 0; i < 10; i++)
    {
        add_to_list(dog, false, i);
    }
}


struct test_struct* create_list(struct dogType *pet, int hashnumber)
{
    struct test_struct *ptr = (struct test_struct*)malloc(sizeof(struct test_struct));

    if(NULL == ptr)
    {
    printf("\n Node creation failed \n");
    return NULL;
    }
    ptr->dog = *pet;
    ptr->next = NULL;

    map[hashnumber].head = map[hashnumber].curr = ptr;
    return ptr;
}



struct test_struct* add_to_list(struct dogType *pet, bool add_to_end, int hashnumber)
{

    if(NULL == ( map[hashnumber].head))
    {
    return (create_list(pet, hashnumber));
    }

    struct test_struct *ptr = (struct test_struct*)malloc(sizeof(struct test_struct));
    if(NULL == ptr)
    {
    printf("\n Node creation failed \n");
    return NULL;
    }

    ptr->dog = *pet;
    ptr->next = NULL;

    if(add_to_end)
    {
     map[hashnumber].curr->next = ptr;
     map[hashnumber].curr = ptr;
    }
    else
    {
    ptr->next = map[hashnumber].head;
    map[hashnumber].head = ptr;
    }

    counter++;
    return ptr;
}

struct test_struct* search_in_list(char * name, struct test_struct **prev, int hashnumber)
{
    struct test_struct *ptr =  map[hashnumber].head;
    struct test_struct *tmp = NULL;
    bool found = false;

    printf("\n Searching the list for value [] \n");

    while(ptr != NULL)
    {
       char *asd=ptr->dog.nombre;
       if(strcmp(asd, name) == 0)
    {
        found = true;
        break;
    }
    else
    {
        tmp = ptr;
        ptr = ptr->next;
    }
    }

    if(true == found)
    {
    if(prev)
        *prev = tmp;
    return ptr;
    }
    else
    {
    return NULL;
    }
}


int delete_from_list(char * name, int hashnumber)
{
    struct test_struct *prev = NULL;
    struct test_struct *del = NULL;

    del = search_in_list(name, &prev, hashnumber);
    if(del == NULL)
    {
    return -1;
    }
    else
    {
    if(prev != NULL)
        prev->next = del->next;

    if(del ==  map[hashnumber].curr)
    {
         map[hashnumber].curr = prev;
    }
    else if(del ==  map[hashnumber].head)
    {
         map[hashnumber].head = del->next;
    }
    }

    free(del);
    del = NULL;
    counter--;

    return 0;
}

void print_list(int hashnumber)
{
    struct test_struct *ptr =  map[hashnumber].head;

    printf("\n -------Printing list Start------- \n");
    while(ptr != NULL)
    {
    printf
    ("\n%s%s", "Nombre: ", ptr->dog.nombre);

    ptr = ptr->next;
    }
    printf("\n -------Printing list End------- \n");

    return;
}

void main(void)
{

    map = nodes;
    dog = malloc(sizeof (struct dogType));
    ini();

       strcpy(dog->nombre, "perrito");
       dog->edad = 15;
       strcpy(dog->raza, "chanda");
       dog->estatura = 15;
       dog->peso = 15;
       dog->sexo = 'm';

    char *filepath = "temp.dat";

    int fd = open(filepath, O_RDWR | O_CREAT , (mode_t)0600);

    if (fd == -1)
    {
    perror("Error opening file for writing");
    exit(EXIT_FAILURE);
    }

    size_t textsize = sizeof(nodes);

    if (lseek(fd, textsize-1, SEEK_SET) == -1)
    {
    close(fd);
    perror("Error calling lseek() to 'stretch' the file");
    exit(EXIT_FAILURE);
    }

    if (write(fd, "", 1) == -1)
    {
    close(fd);
    perror("Error writing last byte of the file");
    exit(EXIT_FAILURE);
    }

    map = mmap(nodes, sizeof(nodes), PROT_READ | PROT_WRITE,  MAP_SHARED, fd, 0);
    if (map == MAP_FAILED)
    {
    close(fd);
    perror("Error mmapping the file");
    exit(EXIT_FAILURE);
    }


    add_to_list(dog, false, 1);
    print_list(1);

    if (msync(map, sizeof(nodes), MS_SYNC) == -1)
    {
    perror("Could not sync the file to disk");
    }

    if (munmap(map, sizeof(nodes)) == -1)
    {
    close(fd);
    perror("Error un-mmapping the file");
    exit(EXIT_FAILURE);
    }

    close(fd);
}

阅读代码:

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <stdint.h>

struct dogType
{
    char nombre[32];
    int edad;
    char raza[16];
    int estatura;
    float peso;
    char sexo;
};

struct dogType *dog;

struct test_struct
{
    struct dogType dog;
    struct test_struct *next;
};

struct node
{
    struct test_struct *head;
    struct test_struct *curr;
};

struct node nodes[10];
struct node *map;

int i;
long counter = 0;

struct test_struct* add_to_list(struct dogType *pet, bool add_to_end, int hashnumber);


void ini(void)
{
    strcpy(dog->nombre, "");
    dog->edad = 0;
    strcpy(dog->raza, "");
    dog->estatura = 0;
    dog->peso = 0;
    dog->sexo = ' ';

    for(i = 0; i < 10; i++)
    {

        add_to_list(dog, false, i);
    }
}


struct test_struct* create_list(struct dogType *pet, int hashnumber)
{
    struct test_struct *ptr = (struct test_struct*)malloc(sizeof(struct test_struct));

    if(NULL == ptr)
    {
    printf("\n Node creation failed \n");
    return NULL;
    }
    ptr->dog = *pet;
    ptr->next = NULL;

    map[hashnumber].head = map[hashnumber].curr = ptr;
    return ptr;
}



struct test_struct* add_to_list(struct dogType *pet, bool add_to_end, int hashnumber)
{

    if(NULL == ( map[hashnumber].head))
    {
    return (create_list(pet, hashnumber));
    }

    struct test_struct *ptr = (struct test_struct*)malloc(sizeof(struct test_struct));
    if(NULL == ptr)
    {
    printf("\n Node creation failed \n");
    return NULL;
    }

    ptr->dog = *pet;
    ptr->next = NULL;

    if(add_to_end)
    {
     map[hashnumber].curr->next = ptr;
     map[hashnumber].curr = ptr;
    }
    else
    {
    ptr->next = map[hashnumber].head;
    map[hashnumber].head = ptr;
    }

    counter++;
    return ptr;
}

struct test_struct* search_in_list(char * name, struct test_struct **prev, int hashnumber)
{
    struct test_struct *ptr =  map[hashnumber].head;
    struct test_struct *tmp = NULL;
    bool found = false;

    printf("\n Searching the list for value [] \n");

    while(ptr != NULL)
    {
       char *asd=ptr->dog.nombre;
       if(strcmp(asd, name) == 0)
    {
        found = true;
        break;
    }
    else
    {
        tmp = ptr;
        ptr = ptr->next;
    }
    }

    if(true == found)
    {
    if(prev)
        *prev = tmp;
    return ptr;
    }
    else
    {
    return NULL;
    }
}


int delete_from_list(char * name, int hashnumber)
{
    struct test_struct *prev = NULL;
    struct test_struct *del = NULL;

    del = search_in_list(name, &prev, hashnumber);
    if(del == NULL)
    {
    return -1;
    }
    else
    {
    if(prev != NULL)
        prev->next = del->next;

    if(del ==  map[hashnumber].curr)
    {
         map[hashnumber].curr = prev;
    }
    else if(del ==  map[hashnumber].head)
    {
         map[hashnumber].head = del->next;
    }
    }

    free(del);
    del = NULL;
    counter--;

    return 0;
}

void print_list(int hashnumber)
{
    struct test_struct *ptr =  map[hashnumber].head;

    printf("\n -------Printing list Start------- \n");
    while(ptr != NULL)
    {
    printf
    ("\n%s%s", "Nombre: ", ptr->dog.nombre);

    ptr = ptr->next;
    }
    printf("\n -------Printing list End------- \n");

    return;
}

void main(void)
{

    ini();

    dog = malloc(sizeof (struct dogType));
    strcpy(dog->nombre, "perrito");
    dog->edad = 15;
    strcpy(dog->raza, "chanda");
    dog->estatura = 15;
    dog->peso = 15;
    dog->sexo = 'm';

    const char *filepath = "temp.dat";

    int fd = open(filepath, O_RDONLY, (mode_t)0600);

    if (fd == -1)
    {
    perror("Error opening file for writing");
    exit(EXIT_FAILURE);
    }        

    struct stat fileInfo = {0};

    if (fstat(fd, &fileInfo) == -1)
    {
    perror("Error getting the file size");
    exit(EXIT_FAILURE);
    }

    if (fileInfo.st_size == 0)
    {
    fprintf(stderr, "Error: File is empty, nothing to do\n");
    exit(EXIT_FAILURE);
    }

    printf("File size is %ji\n", (intmax_t)fileInfo.st_size);

    struct node *map = mmap(nodes, fileInfo.st_size, PROT_READ, MAP_SHARED, fd, 0);

    if (map == MAP_FAILED)
    {
    close(fd);
    perror("Error mmapping the file");
    exit(EXIT_FAILURE);
    }

    print_list(3);

    if (munmap(map, fileInfo.st_size) == -1)
    {
    close(fd);
    perror("Error un-mmapping the file");
    exit(EXIT_FAILURE);
    }

    close(fd);
}

1 个答案:

答案 0 :(得分:1)

看起来你正在尝试创建一个常规文件,写入它,然后使用它的文件描述符作为mmap的参数。

你真正想做的事(我认为)只是在两个进程之间共享内存。

POSIX系统为此目的提供shm_open

int fd = shm_open("/dog_storage", oflags, mode);

pointer = mmap(NULL, length, prot, mmap_flags, fd, offset);

注意NULL作为地址传递。我们让内核决定在哪里找到内存,而不是自己决定。几乎总是如此。

Mmap不会指向真实内存,它会为您的进程提供映射到物理内存。因此,您的读者和作者将最终得到两个不同的指针,但他们将与同一个物理内存对话。

完成后不要忘记shm_unlink