简体   繁体   English

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

[英]Multiple tests in shared memory between parent and child in C

I am writing a program that does multiple writing and reading tests between a parent and a child processes (One of them has the work of writing in a shared memory block and the other one has the work of reading what the other process wrote), well, I saw that this is a producer-consumer problem that would be synchronized by semaphores but I don't get it to work properly (I got them to turn each other for the actions they have to do but it gets a time when they just de synchronize and the reading line doesn't catch what the other process writes).我正在编写一个程序,该程序在父进程和子进程之间进行多次读写测试(其中一个负责在共享内存块中写入,另一个负责读取另一个进程所写的内容),好吧,我看到这是一个生产者 - 消费者问题,可以通过信号量同步,但我没有让它正常工作(我让他们互相转动以完成他们必须做的动作,但有时他们只是de synchronize 并且读取行不会捕获其他进程写入的内容)。 Hope someone could help me using pretty much anything else than shm and sem.希望有人可以帮助我使用除了 shm 和 sem 之外的任何东西。

The following is my main code:以下是我的主要代码:

#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;
}

The next is shared_memory.h接下来是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

The next is shared_memory.c接下来是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);
}

And the following is one of the possible output I get:以下是我得到的可能输出之一:

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.

You have race conditions due to both processes sharing the concern of creating and destroying the shared memory segments, in an uncontrolled order.由于两个进程以不受控制的顺序共享创建和销毁共享内存段的关注,因此您有竞争条件

Error en shmget: Invalid argument错误 en shmget: 无效的参数

One process can get ahead of the other and attempt to attach_shm(FILENAME, size) with the next size .一个进程可以领先于另一个进程并尝试将attach_shm(FILENAME, size)与下一个size While this is happening, the other process may still be attached to the existing shared memory.虽然发生这种情况,但其他进程可能仍附加到现有的共享内存。 Thus,因此,

EINVAL A segment for the given key exists, but size is greater than the size of that segment. EINVAL 存在给定键的段,但大小大于该段的大小。

Shared memory is only actually removed when the last process detaches.只有当最后一个进程分离时,共享内存才会真正被删除。 See shmctl(2) for details.有关详细信息,请参阅shmctl(2)

You need to carry the lockstep outside the inner loop, so that it protects the order of creation and destruction.您需要将锁步带在内循环之外,以便它保护创建和销毁的顺序。 Only one process needs to concern itself with scheduling the destruction of the shared memory segment.只有一个进程需要自己关心调度共享内存段的销毁。

In pseudocode:在伪代码中:

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

A separate issue exists with the fill function. fill功能存在一个单独的问题。

memset(bufptr, ch, size); completely fills the shared memory segment with ch .ch完全填充共享内存段。 There is no room for the null-terminating byte (nor do you place one).空终止字节没有空间(也没有放置)。 Thus, strlen(bufptr);因此, strlen(bufptr); and printf("%s", block);printf("%s", block); are Undefined Behaviour .未定义的行为

Various other issues exist, like unused or pointless variables ( status , cnt ), unchecked errors ( fork , sem_open ), error cascading (if ftok fails, several layers of functions each report the same error) and misrepresented values.还存在各种其他问题,例如未使用或无意义的变量( statuscnt )、未经检查的错误( forksem_open )、错误级联(如果ftok失败,几层函数各自报告相同的错误)和错误表示的值。 As pointed out in the comments, shmat returns (void *) -1 on error, and likewise ftok returns (key_t) -1 .正如评论中所指出的, shmat在错误时返回(void *) -1 ,同样ftok返回(key_t) -1

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM