Ошибка при операциях над элементами в общей памяти C

Я написал этот код, который вставляет структуру в общую память. Я сделал отладочные отпечатки, чтобы попытаться выяснить, где остановились процессы и почему произошла ошибка. Видимо, при выполнении операций над элементами в общей памяти возникает ошибка, но я не понимаю, почему. Как я могу это решить?

static shared_pid_data *shared_pid_atom;

static int shmidA;
static int semidA;

void atomSharedPidInit(){
    key_t key = ftok("shmfileA",65);
    printf("atomSharedPidInit - key = ftok\n");
    shmidA = shmget(key, sizeof(shared_pid_data), 0666|IPC_CREAT);
    printf("atomSharedPidInit - shmget\n");
    shared_pid_atom = (shared_pid_data*) shmat(shmidA, (void*)0, 0);
    printf("atomSharedPidInit - shmat\n");
    key_t sem_key = ftok("semfileA", 75);
    printf("atomSharedPidInit - sem_key = ftok\n");
    semidA = semget(sem_key, 1, 0666 | IPC_CREAT);
    printf("atomSharedPidInit - semget\n");
    semctl(semidA, 0, SETVAL, 1);
    printf("atomSharedPidInit - semctl\n");
}

void lockA() {
    struct sembuf sba = {(unsigned short) 0, -1, 0};
    semop(semidA, &sba, 1);
}

void unlockA() {
    struct sembuf sba = {(unsigned short) 0, 1, 0};
    semop(semidA, &sba, 1);
}

void atomSharedPidWrite(pid_t pid) {
    lockA();
    printf("atomSharedPidWrite - lock\n");
    int dim = shared_pid_atom->dimensione;
    printf("atomSharedPidWrite - int dim\n");
    if (dim < 1000) {
        printf("atomSharedPidWrite - if\n");
        shared_pid_atom->atomi_pid[shared_pid_atom->dimensione] = pid;
        shared_pid_atom->dimensione++;
        printf("pid : %d  dimensione : %d ",shared_pid_atom->atomi_pid[shared_pid_atom->dimensione-1],shared_pid_atom->dimensione);
    } else {
        fprintf(stderr, "Shared memory is full\n");
    }
    unlockA();
}

int main (){
    atomSharedPidInit();
    printf("simulazione - atomSharedPidInit\n");
    alarm((unsigned int)sim_duration);
    printf("simulazione - alarm\n");
    print_statistics();

    for (int i = 0; i < n_atomi_init; i++) {
        atomoPID = fork();
        if (atomoPID == 0) {
            printf("Atomo - fork\n");
            srand((unsigned int)(time(NULL) + getpid()));
            printf("Atomo - srand\n");
            atomSharedPidWrite(getpid());
            printf("Atomo - atomSharedPidWrite(getpid())\n");
            
            int numero_atomico = rand() % max_num_atomico + min_num_atomico;
            printf("%d %d %d ", numero_atomico, max_num_atomico, min_num_atomico);
            char num_atomico_str[10];
            sprintf(num_atomico_str, "%d", numero_atomico);
            execl("./atomo", "./atomo", num_atomico_str, NULL);
            exit(0);
        } else if (atomoPID < -1) {
            kill(getpid(), SIGINT);
            exit(EXIT_FAILURE);
        }
    }
}

вот что я получаю, запустив процесс:

atomSharedPidInit - key = ftok
atomSharedPidInit - shmget
atomSharedPidInit - shmat
atomSharedPidInit - sem_key = ftok
atomSharedPidInit - semget
atomSharedPidInit - semctl
simulazione - atomSharedPidInit
simulazione - alarm
Current state:
Total energy: 0
Total energy consumed: 0
Total energy available: 0
Total atomi attivi: 0
Total scissions: 0
Total activations: 0
Total scorie: 0
+---------------------------------------------------+
Atomo - fork
Atomo - srand
atomSharedPidWrite - lock
Atomo - fork
Atomo - srand
Atomo - fork
Atomo - srand
Atomo - fork
Atomo - fork
Atomo - srand
Atomo - srand
atomSharedPidWrite - lock
atomSharedPidWrite - lock
atomSharedPidWrite - lock
atomSharedPidWrite - lock
make: *** [Makefile:38: run] Errore di segmentazione (creato dump del core)

даже если я проделаю очень банальную операцию, например shared_pid_atom->dimensione = 0;, с общей памятью, она не будет выполнена. Я не понимаю, почему.

В показанном коде отсутствует много информации: предоставьте, пожалуйста, минимально воспроизводимый пример.

G.M. 06.07.2024 12:20
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
1
92
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Я предлагаю вам проверить, действительны ли возвращаемые значения shmidA, semidA и shared_pid_atom: возможно, у вас нет прав на доступ к общей памяти.

Кажется, ваши дочерние процессы умирают раньше, чем

int dim = shared_pid_atom->dimensione;

выполняется, поэтому, возможно, указатель shared_pid_atom недействителен.

Кроме того, ваш замок не работает:

  • вам нужно сначала подождать sem 0, затем вы можете написать значение 1
  • вместо этого в вашем коде вы пишете 1, не дожидаясь нуля, поэтому все процессы запускаются одновременно, как вы видите в журнале.
  • см., например пример использования sem op

Я проверил ваш код, и как только ошибки блокировки исправлены и файлы, используемые для общих ресурсов, существуют, программа работает нормально, и я не вижу необходимости повторно вызывать shmget, вы можете использовать уже имеющийся указатель shared_pid_atom.

#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <sys/wait.h>
#include <unistd.h>
#include <time.h>
#include <signal.h>
#include <errno.h>
#include <string.h>
#include <sys/stat.h>

typedef struct _shared_pid_data
{
    uint32_t dimensione;
    uint32_t atomi_pid[1000];
}shared_pid_data;

static shared_pid_data *shared_pid_atom;

static int shmidA;
static int semidA;

void print_errno_and_die(const char * s)
{
    const int err = errno;
    printf("%s error: %i, %s\n", s, err, strerror(err));
    exit(0);
}

void atomSharedPidInit(){
    printf("+%s\n", __func__);
    struct stat statbuf;
    if (stat("./shmfileA", &statbuf) == -1)
    {
        print_errno_and_die("stat");
    }
    key_t key = ftok("./shmfileA",65);
    printf("\tkey: %i\n", key);
    if (-1 == key)
    {
        print_errno_and_die("key ftok");
    }

    shmidA = shmget(key, sizeof(shared_pid_data), 0666|IPC_CREAT);
    printf("\tshmidA: %i\n", shmidA);
    if (-1 == shmidA)
    {
        print_errno_and_die("shmget");
    }

    shared_pid_atom = (shared_pid_data*) shmat(shmidA, (void*)0, 0);
    printf("\tshared_pid_atom: %p\n", shared_pid_atom);
    if ((void *)-1 == shared_pid_atom)
    {
        print_errno_and_die("shared_pid_atom");
    }

    if (stat("./semfileA", &statbuf) == -1)
    {
        print_errno_and_die("stat semfileA");
    }

    key_t sem_key = ftok("./semfileA", 75);
    printf("\tsem_key: %i\n", sem_key);
    if (-1 == sem_key)
    {
        print_errno_and_die("sem key");
    }

    semidA = semget(sem_key, 1, 0666 | IPC_CREAT);
    printf("\tsemidA has value: %i\n", semidA);
    if (-1 == semidA)
    {
        print_errno_and_die("semidA");
    }

    const int ret_semctl =  semctl(semidA, 0, SETVAL, 0);
    printf("\tsemctl returns: %i\n", ret_semctl);

    if (ret_semctl < 0)
    {
        print_errno_and_die("semctl");
    }

    shared_pid_atom->dimensione = 0;
    printf("-%s\n", __func__);
}

void lockA() {
    struct sembuf sops[2];

    sops[0].sem_num = 0;     
    sops[0].sem_op = 0; // wait for 0
    sops[0].sem_flg = 0;

    sops[1].sem_num = 0;
    sops[1].sem_op = 1; // get the semaphore
    sops[1].sem_flg = 0;

    if (semop(semidA, sops, 2) == -1) {
        perror(__func__);
        exit(EXIT_FAILURE);
    }
}

void unlockA() {

    struct sembuf sops;
    sops.sem_num = 0;
    sops.sem_op = -1; // unlock the semaphore
    sops.sem_flg = 0;

    if (semop(semidA, &sops, 1) == -1) {
        perror(__func__);
        exit(EXIT_FAILURE);
    }
}

void atomSharedPidWrite(pid_t pid) {
    printf("\t+%s: pid %i\n", __func__, pid);
    printf("\t\tpid %i +lockA\n", pid);
    lockA();
    printf("\t\tpid %i -lockA\n", pid);
    int dim = shared_pid_atom->dimensione;
    if (dim < 1000) {
        shared_pid_atom->atomi_pid[shared_pid_atom->dimensione] = pid;
        shared_pid_atom->dimensione++;
        printf("\t\tpid: %u  dimensione: %" PRIu32 "\n",shared_pid_atom->atomi_pid[shared_pid_atom->dimensione-1],shared_pid_atom->dimensione);
    } else {
        fprintf(stderr, "\tShared memory is full\n");
    }
    printf("\t\tpid %i +unlockA\n", pid);
    unlockA();
    printf("\t\tpid %i -unlockA\n", pid);
    printf("\t-%s: pid %i\n", __func__, pid);
}

int main (){
    atomSharedPidInit();

    const int n_atomi_init = 5;

    int atomoPID[n_atomi_init];
    for (int i = 0; i < n_atomi_init; i++) {
        atomoPID[i] = fork();
        if (atomoPID[i] == 0) {
            printf("\tchild %i forked OK with PID %i\n", i, getpid());
            srand((unsigned int)(time(NULL) + getpid()));
            atomSharedPidWrite(getpid());

            const int max_num_atomico = 100;
            const int min_num_atomico = 10;
            int numero_atomico = rand() % max_num_atomico + min_num_atomico;
            printf("\tnumeri: %d %d %d\n", numero_atomico, max_num_atomico, min_num_atomico);
            const int wait_ms = rand() % 200;
            printf("\tchild %i is going to die in %i ms\n", i, wait_ms);
            usleep(wait_ms * 1000);
            //char num_atomico_str[10];
            //sprintf(num_atomico_str, "%d", numero_atomico);
            //execl("./atomo", "./atomo", num_atomico_str, NULL);
            exit(0);
        } else if (atomoPID[i] < -1) {
            printf("\tsomething really bad happened on child %i: atomoPID[i] = %i\n", i, atomoPID[i]);
            kill(getpid(), SIGINT);
            exit(EXIT_FAILURE);
        }
    }

    printf("MAIN: waiting for the children completed OK\n");
    for (int i = 0; i < n_atomi_init; i++)
    {
        int    wstatus;
        waitpid(atomoPID[i], &wstatus, 0);
        printf("MAIN: child %i completed OK\n", i);
    }
    printf("MAIN: all the children completed OK\n");
    printf("MAIN: dimension is %" PRIu32 "\n", shared_pid_atom->dimensione);
    printf("MAIN: bye\n");
}

Выход:

+atomSharedPidInit
        key: 1093279968
        shmidA: 98346
        shared_pid_atom: 0x7f80684f4000
        sem_key: 1261052132
        semidA has value: 1
        semctl returns: 0
-atomSharedPidInit
        child 0 forked OK with PID 95059
        +atomSharedPidWrite: pid 95059
                pid 95059 +lockA
                pid 95059 -lockA
                pid: 95059  dimensione: 1
                pid 95059 +unlockA
                pid 95059 -unlockA
        -atomSharedPidWrite: pid 95059
        child 1 forked OK with PID 95060
        numeri: 13 100 10
        child 0 is going to die in 136 ms
        +atomSharedPidWrite: pid 95060
                pid 95060 +lockA
                pid 95060 -lockA
                pid: 95060  dimensione: 2
                pid 95060 +unlockA
                pid 95060 -unlockA
        -atomSharedPidWrite: pid 95060
        numeri: 76 100 10
        child 1 is going to die in 156 ms
        child 2 forked OK with PID 95061
        +atomSharedPidWrite: pid 95061
                pid 95061 +lockA
                pid 95061 -lockA
                pid: 95061  dimensione: 3
                pid 95061 +unlockA
                pid 95061 -unlockA
        -atomSharedPidWrite: pid 95061
        numeri: 21 100 10
        child 2 is going to die in 102 ms
MAIN: waiting for the children completed OK
        child 3 forked OK with PID 95062
        +atomSharedPidWrite: pid 95062
                pid 95062 +lockA
                pid 95062 -lockA
                pid: 95062  dimensione: 4
                pid 95062 +unlockA
                pid 95062 -unlockA
        -atomSharedPidWrite: pid 95062
        numeri: 24 100 10
        child 4 forked OK with PID 95063
        child 3 is going to die in 137 ms
        +atomSharedPidWrite: pid 95063
                pid 95063 +lockA
                pid 95063 -lockA
                pid: 95063  dimensione: 5
                pid 95063 +unlockA
                pid 95063 -unlockA
        -atomSharedPidWrite: pid 95063
        numeri: 55 100 10
        child 4 is going to die in 195 ms
MAIN: child 0 completed OK
MAIN: child 1 completed OK
MAIN: child 2 completed OK
MAIN: child 3 completed OK
MAIN: child 4 completed OK
MAIN: all the children completed OK
MAIN: dimension is 5
MAIN: bye

дочерний процесс умирает ровно в то время, когда он выполняет эту операцию. Но в этом же коде выполняются аналогичные операции, только в эту общую память я не могу ввести данные.

MiusiZ 06.07.2024 13:22

Пожалуйста, проверьте значения shmidA, semidA и указателяshared_pid_atom; проверьте и распечатайте errno, если они недействительны, и, если можете, сообщите о своих результатах

michele sponchiado 06.07.2024 15:08

Я решил это так: использовал shmat каждый раз, когда мне нужно было получить доступ к памяти.

int atomSharedPidInit(const char *name) {
    key_t key = ftok(name, 65);
    int IDpid = shmget(key, sizeof(shared_pid_data), 0666 | IPC_CREAT);
    shared_pid_atom = (shared_pid_data*) shmat(IDpid, NULL, 0);
    struct shmid_ds shmid_ds;
    if (shmctl(IDpid, IPC_STAT, &shmid_ds) == -1) {
        perror("shmctl");
        exit(1);
    }
    if (shmid_ds.shm_segsz == sizeof(shared_pid_data) && shmid_ds.shm_nattch == 1) {
        shared_pid_atom->dimensione = 0;
    }
    return IDpid;
}

void atomSharedPidWrite(int shmid, pid_t pid) {
    lock();
    shared_pid_data *shared_pid_atom = (shared_pid_data*) shmat(shmid, NULL, 0);
    if (shared_pid_atom == (void*) -1) {
        perror("shmat");
        exit(1);
    }
    if (shared_pid_atom->dimensione < 1000) {
        shared_pid_atom->atomi_pid[shared_pid_atom->dimensione] = pid;
        shared_pid_atom->dimensione++;
    } else {
        fprintf(stderr, "Shared memory is full\n");
    }
    if (shmdt(shared_pid_atom) == -1) {
        perror("shmdt");
        exit(1);
    }
    unlock();
}

Я думаю, что нет необходимости повторно вызывать процедуру shmget, вы можете использовать уже установленный общий_pid_atom, пожалуйста, посмотрите обновленный код в моем ответе, поэтому мне интересно, возникла ли проблема из-за какой-то ошибки в настройке общего доступа (возможно, файлы были не существует?) или в процедуре блокировки/разблокировки.

michele sponchiado 06.07.2024 20:11

Другие вопросы по теме