Я написал этот код, который вставляет структуру в общую память. Я сделал отладочные отпечатки, чтобы попытаться выяснить, где остановились процессы и почему произошла ошибка. Видимо, при выполнении операций над элементами в общей памяти возникает ошибка, но я не понимаю, почему. Как я могу это решить?
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;
, с общей памятью, она не будет выполнена. Я не понимаю, почему.
Я предлагаю вам проверить, действительны ли возвращаемые значения shmidA
, semidA
и shared_pid_atom
: возможно, у вас нет прав на доступ к общей памяти.
Кажется, ваши дочерние процессы умирают раньше, чем
int dim = shared_pid_atom->dimensione;
выполняется, поэтому, возможно, указатель shared_pid_atom
недействителен.
Кроме того, ваш замок не работает:
Я проверил ваш код, и как только ошибки блокировки исправлены и файлы, используемые для общих ресурсов, существуют, программа работает нормально, и я не вижу необходимости повторно вызывать 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
дочерний процесс умирает ровно в то время, когда он выполняет эту операцию. Но в этом же коде выполняются аналогичные операции, только в эту общую память я не могу ввести данные.
Пожалуйста, проверьте значения shmidA, semidA и указателяshared_pid_atom; проверьте и распечатайте errno, если они недействительны, и, если можете, сообщите о своих результатах
Я решил это так: использовал 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, пожалуйста, посмотрите обновленный код в моем ответе, поэтому мне интересно, возникла ли проблема из-за какой-то ошибки в настройке общего доступа (возможно, файлы были не существует?) или в процедуре блокировки/разблокировки.
В показанном коде отсутствует много информации: предоставьте, пожалуйста, минимально воспроизводимый пример.