2015-09-02 3 views
1

Я пытаюсь использовать CK_LIST от http://concurrencykit.org/ через несколько процессов, но когда я это делаю, значения внутри узлов списка являются мусором. Но значения списка верны, когда я использую список только из одного процесса.Как делиться ck_list между процессами?

Ниже приведен пример использования CK_LIST в структуре с помощью одного процесса.

#include <stdio.h> 
#include <stdlib.h> 
#include <ck_queue.h> 

struct shared_map 
{ 
    CK_LIST_HEAD(list, list_node) list; 
}; 

struct list_node 
{ 
    void *data; 

    CK_LIST_ENTRY(list_node) list_entry; 

}; 

int main(void) 
{ 
    struct list_node *node, *node2; 
    struct shared_map mapping = { .list = CK_LIST_HEAD_INITIALIZER(mapping->list) }; 
    struct shared_map *map = &mapping; 

    node = malloc(sizeof(struct list_node)); 
    if(node == NULL) 
    { 
     perror("malloc"); 
     return -1; 
    } 

    CK_LIST_INIT(&map->list); 

    int rtrn = asprintf((char **)&node->data, "test"); 
    if(rtrn < 0) 
    { 
     perror("asprintf"); 
     return -1; 
    } 

    CK_LIST_INSERT_HEAD(&map->list, node, list_entry); 

    CK_LIST_FOREACH(node2, &map->list, list_entry) 
    { 
     printf("out: %s\n", node2->data); 
    } 

    return 0; 
} 

Но когда я пытаюсь использовать список между двумя отдельными процессами значение node->data мусор и вызывает процесс, используя его к краху. Ниже приведен пример.

#include <stdio.h> 
#include <unistd.h> 
#include <sys/mman.h> 
#include <stdlib.h> 
#include <ck_queue.h> 

struct shared_map 
{ 
    CK_LIST_HEAD(list, list_node) list; 
}; 

struct list_node 
{ 
    void *data; 

    CK_LIST_ENTRY(list_node) list_entry; 

}; 

static int create_shared(void **pointer, int size) 
{ 
    *pointer = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_SHARED, -1, 0); 
    if(*pointer == MAP_FAILED) 
    { 
     perror("mmap:"); 
     return -1; 
    } 

    return 0; 
} 

int main(void) 
{ 
    struct list_node *node, *node2; 
    struct shared_map mapping = { .list = CK_LIST_HEAD_INITIALIZER(mapping->list) }; 
    struct shared_map *map = &mapping; 

    int rtrn = create_shared((void **)&map, sizeof(struct shared_map)); 
    if(rtrn < 0) 
    { 
     printf("Can't create shared mapping\n"); 
     return -1; 
    } 

    CK_LIST_INIT(&map->list); 

    pid_t pid; 

    pid = fork(); 
    if(pid == 0) 
    { 
     /* Child. */ 

     node = malloc(sizeof(struct list_node)); 
     if(node == NULL) 
     { 
      perror("malloc"); 
      return -1; 
     } 

     int rtrn = asprintf((char **)&node->data, "test"); 
     if(rtrn < 0) 
     { 
      perror("asprintf"); 
      return -1; 
     } 

     CK_LIST_INSERT_HEAD(&map->list, node, list_entry); 
    } 
    else if(pid > 0) 
    { 
     /* Parent. */ 

     sleep(1); // Make sure child runs first. 

     CK_LIST_FOREACH(node2, &map->list, list_entry) 
     { 
      printf("out: %s\n", node2->data); 
     } 
    } 
    else 
    { 
     perror("fork"); 
     return -1; 
    } 

    return 0; 
} 

CK_LIST перечислен как мульти-чтения одного писателя связанного списка так, я думал, что я только должен был запереть на пишет не читает. Итак, почему node->data становится мусором при использовании его между процессами, а не при использовании одного процесса?

ответ

0

К счастью, это не имеет ничего общего с CK и просто связано с тем, откуда приходит ваша память.

Ваше распределение у ребенка происходит из malloc и живет в адресном пространстве ребенка. Ребенок и родитель не имеют одного и того же адресного пространства (будучи отдельными процессами), поэтому ваше хранилище malloc (3) для узла и данных не имеет адресов в адресном пространстве родителя.

Вам необходимо выделить память для node и node->data из какого-либо общего пространства. Я внес минимальный набор изменений в код, чтобы заставить его работать в демонстрационных целях. Надеюсь, что вы хотите, чтобы ваш API был менее хрупким с точки зрения магических чисел в mmap.

#include <sys/mman.h> 

#include <string.h> 
#include <stdio.h> 
#include <unistd.h> 
#include <stdlib.h> 

#include <ck_queue.h> 

struct shared_map { 
    CK_LIST_HEAD(list, list_node) list; 
}; 

struct list_node { 
    void *data; 
    CK_LIST_ENTRY(list_node) list_entry; 
}; 

static int 
create_shared(void **pointer, int size) 
{ 

    *pointer = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_SHARED, -1, 0); 
    if (*pointer == MAP_FAILED) { 
     perror("mmap:"); 
     return -1; 
    } 

    return 0; 
} 

int 
main(void) 
{ 
    struct list_node *node, *node2; 
    struct shared_map mapping = { .list = CK_LIST_HEAD_INITIALIZER(mapping->list) }; 
    struct shared_map *map = &mapping; 

    int rtrn = create_shared((void **)&map, sizeof(struct shared_map) + sizeof(struct list_node) + 5); 
    if (rtrn < 0) { 
     printf("Can't create shared mapping\n"); 
     return -1; 
    } 

    CK_LIST_INIT(&map->list); 

    pid_t pid; 

    pid = fork(); 
    if (pid == 0) { 
     /* Child. */ 
     node = (struct list_node *)(map + 1); 
     node->data = node + 1; 
     memcpy(node->data, "test", 5); 
     CK_LIST_INSERT_HEAD(&map->list, node, list_entry); 
    } else if (pid > 0) { 
     /* Parent. */ 
     sleep(1); // Make sure child runs first. 

     CK_LIST_FOREACH(node2, &map->list, list_entry) { 
      printf("out: %s\n", (char *)node2->data); 
     } 
    } else { 
     perror("fork"); 
     return -1; 
    } 

    return 0; 
} 

Фундаментально, я просто изменил размер ттар включать пространство для list_node и строку C, прикрепленную к node-> данные и сделал ребенок настроен.