C中父子之间共享内存中的多个测试

Multiple tests in shared memory between parent and child in C

我正在编写一个程序,在父进程和子进程之间进行多次写入和读取测试(其中一个具有在共享内存块中写入的工作,另一个具有读取另一个的工作process wrote), 好吧,我看到这是一个生产者-消费者问题,可以通过信号量同步,但我没有让它正常工作(我让它们互相转换他们必须做的动作但是它得到了他们只是取消同步并且读取行没有捕捉到其他进程写入的内容的时间)。希望有人可以帮助我使用 shm 和 sem 以外的任何东西。

以下是我的主要代码:

#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <semaphore.h>
#include <fcntl.h>

#include "../includes/shared_memory.h"

#define SIZES 6
#define KB 1024
#define SHM_KEY 0x1234

//int PACK_SIZES[SIZES] = {1*KB, 10*KB, 100*KB, 1*1000*KB, 10*1000*KB, 100*1000*KB};
int PACK_SIZES[SIZES] = {1, 2, 3, 4, 5, 6};
int PACK_TESTS[SIZES] = {6,5,4,3,2,1};

int fill(char *bufptr, int size);

int main(){
    int size;
    int tests_amount;
    pid_t pid;

    sem_t *sem1;
    sem_t *sem2;

    sem1 = sem_open("/semaphore1", O_CREAT,  0644, 0);
    sem2 = sem_open("/semaphore2", O_CREAT,  0644, 1);

    pid = fork();
    for (int i = 0; i < SIZES; i++){
        tests_amount = PACK_TESTS[i];
        size = PACK_SIZES[i];

        int status;
        int cnt;

        char *block = attach_shm(FILENAME, size);
        printf("Bloque de tamaño %d creado.\n", size);
        if (block == NULL) {
            printf("No se pudo abrir la memoria compartida\n");
            return -1;
        }

        for (int j = 1; j <= tests_amount; j++){
            if (pid == 0){
                //Productor
                sem_wait(sem2);
                printf("Escritura ShM. Test #%d/%d. Tamaño: %d Bytes.\n", j,tests_amount,size);
                cnt = fill(block, size);
                sem_post(sem1);
            } else {
                //Consumidor
                sem_wait(sem1);
                printf("Lectura ShM. Test #%d/%d. Tamaño: %d Bytes.\n", j,tests_amount,size);
                printf("Contenido: \"%s\"\n\n", block);
                sem_post(sem2);
            }
        }

        detach_shm(block);
        
        if (destroy_shm(FILENAME)){
            printf("Bloque destruido.\n\n");
        } else {
            printf("No se pudo destruir el bloque.\n");
        }
    }
    sem_close(sem1);
    sem_unlink("/semaphore1");
    sem_close(sem2);
    sem_unlink("/semaphore2");
    return 0;
}

int fill(char * bufptr, int size){
    static char ch = 'A';
    int filled_count;

    printf("size is %d\n", size);
    memset(bufptr, ch, size);
    
    if (ch > 90)
        ch = 65;
    
    filled_count = strlen(bufptr);

    printf("Bytes escritos: %d\n\n", filled_count);
    //printf("buffer filled is:%s\n", bufptr);
    ch++;
    return filled_count;
}

下一个是shared_memory.h

#ifndef SHARED_MEMORY_H
#define SHARED_MEMORY_H

#include <stdbool.h>

char * attach_shm(char *filename, int size);
bool detach_shm(char *block);
bool destroy_shm(char *filename);

#define FILENAME "../src/productor.c"

#endif

下一个是shared_memory.c

#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

#include "shared_memory.h"

static int get_shm(char *filename, int size) {
    key_t key;

    key = ftok(filename, 0);

    if (key < 0) {
        perror("Error en Key");
        return -1;
    }

    return shmget(key, size, 0644 | IPC_CREAT);
}

char * attach_shm(char *filename, int size) {
    int shmId = get_shm(filename, size);
    char *ptr;

    if (shmId < 0){
        perror("Error en shmget");
        return NULL;
    }

    ptr = (char *) shmat(shmId, NULL, 0);

    if (ptr < 0){
        perror("Error en shmat");
        return NULL;
    }

    return ptr;
}

bool detach_shm(char *block){
    return (shmdt(block) != -1);
}

bool destroy_shm(char *filename) {
    int shmId = get_shm(filename, 0);

    if (shmId < 0){
        perror("Error en shmget");
        return NULL;
    }
    return (shmctl(shmId, IPC_RMID, NULL) != -1);
}

下面是我可能得到的输出之一:

Bloque de tamaño 1 creado.
Bloque de tamaño 1 creado.
Escritura ShM. Test #1/6. Tamaño: 1 Bytes.
size is 1
Bytes escritos: 1

Lectura ShM. Test #1/6. Tamaño: 1 Bytes.
Contenido: "A"

Escritura ShM. Test #2/6. Tamaño: 1 Bytes.
size is 1
Bytes escritos: 1

Lectura ShM. Test #2/6. Tamaño: 1 Bytes.
Contenido: "B"

Escritura ShM. Test #3/6. Tamaño: 1 Bytes.
size is 1
Bytes escritos: 1

Lectura ShM. Test #3/6. Tamaño: 1 Bytes.
Contenido: "C"

Escritura ShM. Test #4/6. Tamaño: 1 Bytes.
size is 1
Bytes escritos: 1

Lectura ShM. Test #4/6. Tamaño: 1 Bytes.
Contenido: "D"

Escritura ShM. Test #5/6. Tamaño: 1 Bytes.
size is 1
Bytes escritos: 1

Lectura ShM. Test #5/6. Tamaño: 1 Bytes.
Contenido: "E"

Escritura ShM. Test #6/6. Tamaño: 1 Bytes.
size is 1
Bytes escritos: 1

Lectura ShM. Test #6/6. Tamaño: 1 Bytes.
Bloque destruido.

Contenido: "F"

Bloque de tamaño 2 creado.
Escritura ShM. Test #1/5. Tamaño: 2 Bytes.
size is 2
Bytes escritos: 2

Bloque destruido.

Bloque de tamaño 2 creado.
Lectura ShM. Test #1/5. Tamaño: 2 Bytes.
Contenido: ""

Escritura ShM. Test #2/5. Tamaño: 2 Bytes.
size is 2
Bytes escritos: 2

Lectura ShM. Test #2/5. Tamaño: 2 Bytes.
Contenido: ""

Escritura ShM. Test #3/5. Tamaño: 2 Bytes.
size is 2
Bytes escritos: 2

Lectura ShM. Test #3/5. Tamaño: 2 Bytes.
Contenido: ""

Escritura ShM. Test #4/5. Tamaño: 2 Bytes.
size is 2
Bytes escritos: 2

Lectura ShM. Test #4/5. Tamaño: 2 Bytes.
Contenido: ""

Escritura ShM. Test #5/5. Tamaño: 2 Bytes.
size is 2
Bytes escritos: 2

Lectura ShM. Test #5/5. Tamaño: 2 Bytes.
Contenido: ""

Bloque destruido.

Bloque de tamaño 3 creado.
Escritura ShM. Test #1/4. Tamaño: 3 Bytes.
size is 3
Bytes escritos: 3

Bloque destruido.

Bloque de tamaño 3 creado.
Lectura ShM. Test #1/4. Tamaño: 3 Bytes.
Contenido: ""

Escritura ShM. Test #2/4. Tamaño: 3 Bytes.
size is 3
Bytes escritos: 3

Lectura ShM. Test #2/4. Tamaño: 3 Bytes.
Contenido: ""

Escritura ShM. Test #3/4. Tamaño: 3 Bytes.
size is 3
Bytes escritos: 3

Lectura ShM. Test #3/4. Tamaño: 3 Bytes.
Contenido: ""

Escritura ShM. Test #4/4. Tamaño: 3 Bytes.
size is 3
Bytes escritos: 3

Lectura ShM. Test #4/4. Tamaño: 3 Bytes.
Contenido: ""

Bloque destruido.

Bloque de tamaño 4 creado.
Escritura ShM. Test #1/3. Tamaño: 4 Bytes.
size is 4
Bytes escritos: 4

Bloque destruido.

Bloque de tamaño 4 creado.
Lectura ShM. Test #1/3. Tamaño: 4 Bytes.
Contenido: ""

Escritura ShM. Test #2/3. Tamaño: 4 Bytes.
size is 4
Bytes escritos: 4

Lectura ShM. Test #2/3. Tamaño: 4 Bytes.
Contenido: ""

Escritura ShM. Test #3/3. Tamaño: 4 Bytes.
size is 4
Bytes escritos: 4

Lectura ShM. Test #3/3. Tamaño: 4 Bytes.
Contenido: ""

Bloque destruido.

Bloque de tamaño 5 creado.
Escritura ShM. Test #1/2. Tamaño: 5 Bytes.
Bloque destruido.
size is 5

Bytes escritos: 5

Bloque de tamaño 5 creado.
Lectura ShM. Test #1/2. Tamaño: 5 Bytes.
Contenido: ""

Escritura ShM. Test #2/2. Tamaño: 5 Bytes.
size is 5
Bytes escritos: 5

Lectura ShM. Test #2/2. Tamaño: 5 Bytes.
Contenido: ""

Bloque destruido.

Bloque de tamaño 6 creado.
Escritura ShM. Test #1/1. Tamaño: 6 Bytes.
size is 6
Bloque destruido.
Bytes escritos: 6


Bloque destruido.

Bloque de tamaño 6 creado.
Lectura ShM. Test #1/1. Tamaño: 6 Bytes.
Contenido: ""

Error en shmget: Invalid argument
No se pudo destruir el bloque.

由于两个 进程以不受控制的顺序共享创建和销毁共享内存段的问题,因此您有 race conditions

Error en shmget: Invalid argument

一个进程可以领先于另一个进程并尝试 attach_shm(FILENAME, size) 与下一个 size。发生这种情况时,其他进程可能仍附加到现有的共享内存。因此,

EINVAL A segment for the given key exists, but size is greater than the size of that segment.

共享内存仅在最后一个进程分离时才真正删除。有关详细信息,请参阅 shmctl(2)

你需要在内循环外携带lockstep,这样才能保护创建和销毁的顺序。只有一个进程需要关心调度共享内存段的销毁。

在伪代码中:

sem1 := semaphore(0)
sem2 := semaphore(1)

for each size:
    if child: wait sem2
    if parent: wait sem1
    
    block := get_shared_memory(id, size)

    if child: post sem1
    if parent: post sem2

    for each test:
        if child:
            wait sem2
            write_to(block, size)
            post sem1
        if parent:
            wait sem1
            read_from(block, size)
            post sem2

    if child:
        wait sem2
        detach(block)
        schedule_destruction(id)
        post sem1
    if parent:
        wait sem1
        detach(block)
        post sem2

fill 函数存在一个单独的问题。

memset(bufptr, ch, size);ch完全填满共享内存段。 null-terminating 字节没有空间(您也没有放置一个)。因此,strlen(bufptr);printf("%s", block);Undefined Behaviour.

存在各种其他问题,例如未使用或无意义的变量(statuscnt)、未经检查的错误(forksem_open)、错误级联(如果 ftok 失败,几层函数各自报告相同的错误)和错误陈述的值。正如评论中指出的那样,shmat returns (void *) -1 出错,同样 ftok returns (key_t) -1.