I have two codes : PRODUCER (PR) and CONSUMER (CO). There is a block of memory (Mat) (a 3D matrix to be precise) which needs to be shared between both the programs. I am currently using shared memory based IPC functions to share the memory space between the two codes.
Constraints:
- PR is the owner of the
Matand performs iterations changing the values of the matrix. CO is the user of theMatand only reads the values and uses for some further calculation - PR should write the data first and then should wait for the CO to read and use the values of the
Matrixthen signalling PR to proceed with further iteration and it should continue like this.
What I am currently using is -
PRODUCER
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#define NOT_READY -1
#define FILLED 0
#define TAKEN 1
#define nx (400)
#define ny (400)
#define nz (400)
struct Memory {
int status;
double u_x[nx+1][ny+2][nz+2];
}
int
main(int argc, char *argv[])
{
key_t ShmKEY;
int ShmID;
struct Memory *ShmPTR;
int i, j, k;
int niter = 5;
int sumX[niter],sumY[niter],sumZ[niter];
ShmKEY = ftok(".", 'x'); // getting the unique identifier key from directory location
ShmID = shmget(ShmKEY, sizeof(struct Memory), IPC_CREAT | 0666);
if (ShmID < 0) {
printf("*** shmget error (server) ***\n");
exit(1);
}
ShmPTR = (struct Memory *) shmat(ShmID, NULL, 0);
if ((int) ShmPTR == -1) {
printf("*** shmat error (server) ***\n");
exit(1);
}
printf("Server attached the memory to its virtual space...\n");
ShmPTR->status = NOT_READY; // setting the status to be not ready before filling it
for (int m = 0; m < niter; m++){
for (i=0; i<=nx; i++) for (j=0; j<=ny+1; j++) for (k=0; k<=nz+1; k++)
ShmPTR->u_x[i][j][k] = m; // filling the array with iteration number (just for depiction purpose)
ShmPTR->status = FILLED; // change the status to Filled
//printf("Please start the client in another window...\n");
while (ShmPTR->status != TAKEN)
sleep(1);
}
printf("Server has detected the completion of its child...\n");
shmdt((void *) ShmPTR);
printf("Server has detached its shared memory...\n");
shmctl(ShmID, IPC_RMID, NULL);
printf("Server has removed its shared memory...\n");
printf("Server exits...\n");
exit(0);
}
CONSUMER
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#define NOT_READY -1
#define FILLED 0
#define TAKEN 1
#define nx (400)
#define ny (400)
#define nz (400)
struct Memory {
int status;
double u_x[nx+1][ny+2][nz+2];
}
int
main(void)
{
key_t ShmKEY;
int ShmID;
struct Memory *ShmPTR;
int i, j, k;
int niter = 5;
int sumX[niter];
ShmKEY = ftok(".", 'x');
ShmID = shmget(ShmKEY, sizeof(struct Memory), 0666);
if (ShmID < 0) {
printf("*** shmget error (client) ***\n");
exit(1);
}
printf("Client has received a shared memory...\n");
ShmPTR = (struct Memory *) shmat(ShmID, NULL, 0);
if ((int) ShmPTR == -1) {
printf("*** shmat error (client) ***\n");
exit(1);
}
printf("Client has attached the shared memory to it's virtual memory space...\n");
for (int m =0; m<niter; m++){
sumX[m] = 0;
while (ShmPTR->status != FILLED)
;
printf("Client found the data is ready, performing sanity check...\n");
// read the integers and check for the sum
for (i=0; i<=nx; i++) for (j=0; j<=ny+1; j++) for (k=0; k<=nz+1; k++)
sumX[m] += ShmPTR->u_x[i][j][k];
printf("Cycle %d : sumX-> %d\n", m,sumX[m);
ShmPTR->status = TAKEN;
printf("Client has informed server data have been taken...\n");
}
shmdt((void *) ShmPTR);
printf("Client has detached its shared memory...\n");
printf("Client exits...\n");
exit(0);
}
What I am doing right now is using a member of the struct called status to kind of prevent race conditions. From what I have read till now, semaphores allow a similar thing in IPC.
Question: How to use semaphore in this such that the memory space which needs to be shared is just the array(s) and not wrapping it in a struct with a self defined flag ?
Edit1: Or maybe mutex for that matter if it is better than semaphore for this application.
Edit2: Following @Stargateur answer which works for this code but in the production code where nx, ny and nz are variables, how does one define a shared memory for the struct consisting of a member which is a variable length multidimensional array ? ( ofcourse it would live until the call shmdt and shmctl )