Как использовать общую память для двух процессов С линукс

152
11 июня 2019, 15:10

Нужно сделать общим для нескольких процессов массив структур. Решил сделать так: один из процессов выделяет общий блок памяти с помощью shmget, другие процессы подгружают к себе указатель на этот блок памяти. Когда нужно записать значение в поле элемента массива, делаю так: ((PRUNNING_CONTEXT)(shm + (sizeof(RUNNING_CONTEXT) * i)))->name , т.е. смещаю указатель в общей области на количество элементов, преобразую к указателю на элемент массива, и обращаюсь к полю. По неизвестной причине при попытке записи/чтения через contextByNum(num)->field получаю segmentation fault(core dumped).

В initContexts выделяется блок памяти, в него копируется пустой массив с помощью memcpy, затем с помощью commonSetupContext выполняется начальная инициализация. В main вызывается initContexts, затем выводятся все имена контекстов. Падает в commonSetupContext при попытке strcpy(pContext->name, getProcessName(num)). Для интереса пробовал убрать strcpy - падает при обращении к любому полю, как для записи так и для чтения.

//runningContext.h
typedef struct _runningContext {
    int num;
    int numNextActiveContext;
    int active;
    int pid;
    int ppid;
    int pgid;
    char name[NAME_SIZE];
    int replaceAmount;
    int replaceNums[REPLACE_NUMS_SIZE];
    int killId;
    int killSig;
    int killUsr;
    int usrRec;
    int usr1Rec;
    int usr2Rec;
    int currRecAmount;
    int needRecAmount;
} RUNNING_CONTEXT, *PRUNNING_CONTEXT;
extern RUNNING_CONTEXT contexts[PROCESSES_AMOUNT];
extern int shmKey;
extern int shmId;
extern char* shm;
//runningContext.c
void initContexts() {
    shmId = shmget(shmKey, sizeof(contexts), IPC_CREAT | 0666);
    if(shmId < 0) {
        logerror("Fatal! Can't shmget");
        exit(1);
    }
    shm = shmat(shmId, NULL, 0);
    if(shm == (char*)-1) {
        logerror("Fatal! Can't shmat");
        exit(1);
    }
    memcpy(shm, contexts, sizeof(contexts));
    for(int i = 0; i<PROCESSES_AMOUNT; ++i) {
        commonSetupContext(contextByNum(i + 1), i + 1);
    }
}

void loadContexts() {
    shmId = shmget(shmKey, sizeof(contexts), 0666);
    if(shmId < 0) {
        logerror("Fatal! Can't shmget");
        exit(1);
    }
    shm = shmat(shmId, NULL, 0);
    if(shm == (char*)-1) {
        logerror("Fatal! Can't shmat");
        exit(1);
    }
}
void commonSetupContext(PRUNNING_CONTEXT pContext, int num) {
    strcpy(pContext->name, getProcessName(num));
    pContext->num = num;
    logerror("debug");
    pContext->pid = PROCESS_ID_NOT_SET;
    pContext->replaceAmount = 0;
    pContext->usrRec = 0;
    pContext->usr2Rec = 0;
}
PRUNNING_CONTEXT contextByNum(int num) {
    if(isNumExists(num) == FALSE) {
        logerror("Num not exists, custom error");
        return NULL;
    }
    for(int i = 0; i<PROCESSES_AMOUNT; ++i) {
        if(((PRUNNING_CONTEXT)(shm + (sizeof(RUNNING_CONTEXT) * i)))->num == num) {
            return (PRUNNING_CONTEXT)(shm + (sizeof(RUNNING_CONTEXT) * i));
        }
    }
    return NULL;
}
//main
initContexts();
for(int i = 0; i<PROCESSES_AMOUNT; ++i) {
    logerror("%d. %d", contextByNum(i + 1)->name);
}
Answer 1

При вызове commonSetupContext() первым параметром идет вызов contextByNum(), который ищет контекст по номеру ... Но судя по содержимому commonSetupContext этот самый номер будет установлен им. Следовательно в момент первого вызова contextByNum номера еще нет в структуре и эта функция возвращает NULL ...

Вообще я бы делал примерно так:

RUNNING_CONTEXT *contexts;
...
shmId = shmget(shmKey, sizeof(RUNNING_CONTEXT)*PROCESSES_AMOUNT, IPC_CREAT | 0666);
...
contexts=(RUNNING_CONTEXT *)shm;
// Вместо (PRUNNING_CONTEXT)(shm + (sizeof(RUNNING_CONTEXT) * i)))->num
contexts[i]->num

И если эти самые num не случайны, а как в вашем примере идут подряд, то их поиск так же не нужен, ибо &contexts[num-1] уже готовый адрес нужной структуры.

READ ALSO
Как переводится instantiation?

Как переводится instantiation?

Видел множество вариантов: инстанциация, инстанцирование, инстанцианирование и тп

158
Java Spring соединение из докер-контейнера с БД

Java Spring соединение из докер-контейнера с БД

Хочу запустить свой сервис, написанный на спринге, в докер-контейнереСервис работает с RethinkDB, который уже запущен в контейнере

109
Поиск суммы цифр числа независимо от длины с помощью лямбда выражения в Java

Поиск суммы цифр числа независимо от длины с помощью лямбда выражения в Java

Пытаюсь решить задачу на Java именно с помощью лямбда выражения

119