在C中的子级和父级之间共享链表

在C中的子级和父级之间共享链表,c,fork,shared-memory,C,Fork,Shared Memory,我有一个链表。我有很多子进程处理这个链表,添加和删除元素。如何在所有的孩子之间分享 我已经尝试过使用内存映射的代码: #include <stdio.h> #include <sys/types.h> #include <sys/mman.h> #include <err.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include

我有一个链表。我有很多子进程处理这个链表,添加和删除元素。如何在所有的孩子之间分享

我已经尝试过使用内存映射的代码:

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

typedef struct Struttura
{
    int prova;
    struct Struttura* next;
} Struttura;

Struttura* glob;
int main()
{
    int fd = open("/dev/zero", O_RDWR, 0);
    glob = mmap(NULL, sizeof(Struttura), PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED, fd, 0);

    int pid = fork();
    if(pid == 0)
    {
        printf("Glob value: %d\n", glob->prova);
        glob->next = mmap(NULL, sizeof(Struttura), PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED, fd, 0);
        glob->next->prova = 3;
        printf("The next value: %d\n\n", glob->next->prova);
        return (0);
    }
    else
    {
        wait(NULL);
        printf("Glob value: %d\n", glob->prova);
        printf("The next value: %d\n\n", glob->next->prova); //Segmentation fault core dumped
    }
    return (0);
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
类型定义结构Struttura
{
int prova;
Struttura结构*next;
}斯特拉图拉;
Struttura*glob;
int main()
{
int fd=打开(“/dev/zero”,O_RDWR,0);
glob=mmap(NULL,sizeof(Struttura),PROT_READ | PROT_WRITE,MAP|u FILE | MAP|u SHARED,fd,0);
int-pid=fork();
如果(pid==0)
{
printf(“全局值:%d\n”,全局->prova);
glob->next=mmap(NULL,sizeof(Struttura),PROT_READ | PROT_WRITE,MAP_FILE | MAP_SHARED,fd,0);
全局->下一步->prova=3;
printf(“下一个值:%d\n\n”,glob->next->prova);
返回(0);
}
其他的
{
等待(空);
printf(“全局值:%d\n”,全局->prova);
printf(“下一个值:%d\n\n”,glob->next->prova);//分段错误核心转储
}
返回(0);
}
如何做到这一点?请不要介意同步和未检查的返回值,因为这只是一次尝试:)

使用
mmap(2)
,如果不对列表的最大大小施加一些限制,您将很难轻松地完成此操作。原因是很容易分配一大块内存与子进程共享,但在分叉后增加该块内存是不可行的

您可以通过使用XSI共享内存接口(请参见
man 7 shm_概述
):您可以使用
shm_open(3)
创建和访问共享内存块,并且可以使用
ftruncate(2)
设置其大小。从理论上讲,这将给您动态增长和收缩的能力,但代价是更复杂的代码:XSI共享内存对象与MMAMED内存不同,在关闭它或所有进程取消映射对象并使用
shm_unlink(3)
将其删除之前,不会从系统中删除。如果任何进程崩溃并异常终止,则存在清理问题。此外,每次有人更改内存对象的大小时,您都会面临通知其他进程的问题。如果在插入过程中通知进程怎么办?如果一个进程正在将一个节点插入一个不再存在的内存位置,因为有人同时缩小了它的大小,该怎么办

您并没有真正提到为什么要尝试这样做,但在所有情况下,您最好使用线程。线程在这里是一个更理智、更合理的选择,因为它们正是为了这个目的:方便资源共享。您不必设置共享内存段,并且列表的大小不限于分配的块的大小

无论如何,这里有一个程序的示例,它使用
mmap(2)
创建一个共享内存段,并有一系列子进程从保存在该内存段中的链表中添加和删除元素。前几个内存块用于一些内部事务,即指向列表头和空闲节点列表的指针,以及用于同步访问的互斥体。我们需要保留一个空闲节点列表,以便工作进程在向实际列表添加新节点时可以找到空闲节点。每个辅助进程(共有10个)将10个新节点插入存储辅助进程ID的列表中。每次插入后,辅助进程将打印整个列表。插入所有这些节点后,工作进程将它们从列表中删除并终止

请注意,列表的最大大小是1024,因为这是我们分配的

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <pthread.h>
#include <assert.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/wait.h>

#define MAX_LIST_SZ 1024
#define WORKERS 10
#define WORK_UNIT 10

struct list_node {
    long value;
    struct list_node *next;
};

static struct list_node **list_head;
static struct list_node **free_head;
static pthread_mutex_t *mutex;

void print_list(void) {
    struct list_node *curr = *list_head;

    while (curr != NULL) {
        printf("%ld -> ", curr->value);
        curr = curr->next;
    }

    printf("NULL\n");
}

void do_work(void) {
    int i;
    for (i = 0; i < WORK_UNIT; i++) {
        pthread_mutex_lock(mutex);

        struct list_node *n = *free_head;

        if (n == NULL) {
            pthread_mutex_unlock(mutex);
            assert(0);
        }

        *free_head = (*free_head)->next;
        n->value = (long) getpid();
        n->next = *list_head;
        *list_head = n;

        print_list();

        pthread_mutex_unlock(mutex);
    }

    for (i = 0; i < WORK_UNIT; i++) {
        pthread_mutex_lock(mutex);
        struct list_node *n = *list_head;
        *list_head = (*list_head)->next;
        n->next = *free_head;
        *free_head = n;
        pthread_mutex_unlock(mutex);
    }

}

int main(void) {
    void *ptr;
    size_t region_sz = 0;

    /* Space for the nodes */
    region_sz += sizeof(**list_head)*MAX_LIST_SZ;

    /* Space for house-keeping pointers */
    region_sz += sizeof(list_head)+sizeof(free_head);

    /* Space for the mutex */
    region_sz += sizeof(*mutex);

    ptr = mmap(NULL, region_sz, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, 0, 0);
    if (ptr == MAP_FAILED) {
        perror("mmap(2) failed");
        exit(EXIT_FAILURE);
    }

    /* Set up everything */
    mutex = ptr;
    free_head = (struct list_node **) (((char *) ptr)+sizeof(*mutex));
    list_head = free_head+1;

    *free_head = (struct list_node *) (list_head+1);
    *list_head = NULL;

    /* Initialize free list */
    int i;
    struct list_node *curr;

    for (i = 0, curr = *free_head; i < MAX_LIST_SZ-1; i++, curr++) {
        curr->next = curr+1;
    }

    curr->next = NULL;

    pthread_mutexattr_t mutex_attr;
    if (pthread_mutexattr_init(&mutex_attr) < 0) {
        perror("Failed to initialize mutex attributes");
        exit(EXIT_FAILURE);
    }

    if (pthread_mutexattr_setpshared(&mutex_attr, PTHREAD_PROCESS_SHARED) < 0) {
        perror("Failed to change mutex attributes");
        exit(EXIT_FAILURE);
    }

    if (pthread_mutex_init(mutex, &mutex_attr) < 0) {
        perror("Failed to initialize mutex");
        exit(EXIT_FAILURE);
    }

    for (i = 0; i < WORKERS; i++) {
        pid_t pid;
        if ((pid = fork()) < 0) {
            perror("fork(2) error");
            exit(EXIT_FAILURE);
        }

        if (pid == 0) {
            do_work();
            return 0;
        }
    }

    for (i = 0; i < WORKERS; i++) {
        if (wait(NULL) < 0) {
            perror("wait(2) error");
        }
    }

    assert(*list_head == NULL);

    return 0;
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#定义MAX_LIST_SZ 1024
#定义工人10
#定义工作单元10
结构列表节点{
长期价值;
结构列表\节点*下一步;
};
静态结构列表\节点**列表\头;
静态结构列表节点**自由头;
静态pthread_mutex_t*mutex;
作废打印列表(作废){
结构列表节点*curr=*列表头;
while(curr!=NULL){
printf(“%ld->”,当前->值);
当前=当前->下一步;
}
printf(“NULL\n”);
}
无效工作(无效){
int i;
对于(i=0;i<工作单位;i++){
pthread_mutex_lock(互斥锁);
结构列表\u节点*n=*自由\u头;
如果(n==NULL){
pthread_mutex_unlock(互斥锁);
断言(0);
}
*自由头=(*自由头)->下一步;
n->value=(长)getpid();
n->next=*列表头;
*列表头=n;
打印列表();
pthread_mutex_unlock(互斥锁);
}
对于(i=0;i<工作单位;i++){
pthread_mutex_lock(互斥锁);
结构列表\节点*n=*列表\头;
*列表头=(*列表头)->下一步;
n->next=*自由头;
*自由水头=n;
pthread_mutex_unlock(互斥锁);
}
}
内部主(空){
无效*ptr;
大小_t区域_sz=0;
/*节点的空间*/
区域(sz+)=规模(**列表(头部)*最大列表(sz);
/*房屋管理指针的空间*/
区域(sz+)=sizeof(列表)和sizeof(自由);;
/*互斥空间*/
区域_sz+=sizeof(*互斥);
ptr=mmap(NULL,region|u sz,PROT|u READ | PROT|u WRITE,MAP|u SHARED | MAP|u ANONYMOUS,0,0);
如果(ptr==MAP_失败){
perror(“mmap(2)失败”);
退出(退出失败);
}
/*安排一切*/
互斥=ptr;
自由头=(结构列表节点**)((char*)ptr)+sizeof(*mutex));
列表头=自由头+1;
*自由头=(结构列表节点*)(列表头+1);
*列表头=空;
/*初始化自由列表*/
int i;
结构列表\u节点*curr;
对于(i=0,curr=*free_head;i下一步=当前+1;
}
当前->下一步=空;
pthread_mutextatr_t mutex_attr;
if(pthread\u mutexattr\u init(&mutex\u attr)<0){
perror(“未能初始化互斥对象属性
1) do not cast the return value.
2) always check the returned value for MAP_FAILED which indicates the operation failed
1) when pid <  0 then an error occurred
2) when pid == 0 then child executing
3) when pid >  0 then parent executing