[英]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.还存在各种其他问题,例如未使用或无意义的变量(
status
、 cnt
)、未经检查的错误( fork
、 sem_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.