Reputation: 25
I have a project to illustrate how to use shared memory in C. And this is my suggested assignment for my project this semester: adding up all elements in a 2d array, in a special way:
- take input from user the row size (m) and column size (n), for example m = 4, n = 3.
- the program will be called, for example: myadder 9 8 7 3 2 1 2 3 4 2 10 12 (these 12 numbers input are separated by white-space or return key)
- create a shared memory 1d array of enough size to hold the entire above 2d array
- then, create a shared memory 1d array of the size of the number of rows m. This array will be used to store the totals of each of the rows after it is calculated
- the program then fork off a child process for each row in the array. This child process will total up its associated row and only it's row from shared memory, and store result in its associated element in another 1d array, called total_row
- The parent process will wait until all children have finished, then add up all elements in total_row.
Can you give me hints to finish the above task?
Upvotes: 1
Views: 6895
Reputation: 11
Consider the following array declaration:
int arr[8];
What happens in memory when we make this declaration?
32 bytes are immediately reserved in memory, 4 bytes each for the 8 integers. Since the array is not being initialized, all 8 values present in it would be garbage values.
This happens because the storage class of this array is assumed to be AUTO. If the storage class is declared to be STATIC, then all of the array elements would have a default initial value of 0.
Whatever be the initial values, all of the array elements would always be present in contiguous memory locations.
This arrangement of array elements in memory is shown in fig.
12 34 66 -45 23 346 77 90
65508 65512 65516 65520 65524 65528 65532 65536
Upvotes: 1
Reputation: 21
This below code uses 2 shared memory segments..
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/wait.h>
#define KEY_2D 12345
#define KEY_ROW 54321
int main(int argc, char **argv) {
int rows, cols;
scanf("%d %d", &rows, &cols);
if(rows <= 0 || cols <= 0) {
printf("invalid input\n");
return 1;
}
int *dataa_user = NULL; /* To get user input for 2D array */
int i = 0;
int shm_2d = -1;
dataa_user = (int *) malloc(rows * cols * sizeof(int));
/* Do you need to take input from user as 2D array? and then
* convert it back to 1D array?
* I wonder as this is probably your assignment to understand
* some C and Unix concepts
*/
for(i = 0; i < rows * cols; i ++)
scanf("%d", &dataa_user[i]);
/* Creating shared memory that holds 2D array as 1D array */
shm_2d = shmget(KEY_2D, rows * cols * sizeof (int), IPC_CREAT | 0666);
if(shm_2d < 0) {
perror("shmget");
if(dataa_user) free(dataa_user);
dataa_user = NULL;
return 1;
}
/* Attach to the shared memory */
void *data_2d = shmat(shm_2d, NULL, 0);
if(data_2d == (void *)-1) {
perror("shmat");
shmctl (shm_2d, IPC_RMID, NULL);
if(dataa_user) free(dataa_user);
dataa_user = NULL;
return 1;
}
int shm_row = -1;
/* Copy the 1D array to shared memory */
memcpy( data_2d, dataa_user, rows * cols * sizeof(int));
free(dataa_user);
dataa_user = NULL;
/* Creating shared memory to keep the sum of each row as 1D array */
shm_row = shmget(KEY_ROW, rows * sizeof (int), IPC_CREAT | 0666);
if(shm_row < 0) {
perror("shmget");
shmdt(data_2d);
shmctl (shm_2d, IPC_RMID, NULL);
return 1;
} /* this closing brace was missed when i posted it first time.. */
/* Attach to the shared memory */
void *data_row = shmat(shm_row, NULL, 0);
if(data_row == (void *)-1) {
perror("shmat");
shmdt (data_2d);
shmctl (shm_2d, IPC_RMID, NULL);
shmctl (shm_row, IPC_RMID, NULL);
return 1;
}
/* Initialize it to 0. */
memset(data_row, 0, rows * sizeof(int));
for(i = 0; i < rows; i ++) {
if(!fork()) {
int k = 0;
int *dataa_2d = (int *)data_2d;
int *total_row = (int *)data_row;
for(; k < cols; k ++)
total_row[i] += dataa_2d[i * cols + k]; //add data to shm[row index] for each col in that row
return 0;
}
}
int sts = 0;
for(i = 0; i < rows; i ++) {
wait(&sts); /* wait for all the children to exit. */
}
int total_2d = 0;
int *total_row = (int *)data_row;
for(i = 0; i < rows; i ++) {
total_2d += total_row[i]; /* main process adding up all the row sum values */
}
printf("%d\n", total_2d);
/* clean up of IPC(shms used) */
shmdt(data_2d);
shmdt(data_row);
shmctl (shm_2d, IPC_RMID, NULL);
shmctl (shm_row, IPC_RMID, NULL);
return 0;
}
Your problem statement only mandates use of fork() system call.. So, the problem as such is simple (taking advantage of COW)..
(If you were supposed to use exec() system calls, then it might help you understand the reality in linux systems.. Also if totalling of total_row was assigned to each child process, like summing up to 3rd shared memory or something, it would have helped in understanding synchronization.. )
Anyway, hope this helps..
Upvotes: 0
Reputation: 980
I believe this should do the trick:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/wait.h>
int main ()
{
int w, h, i, j;
/* Read the width and height */
scanf ("%d %d", &w, &h);
/* Create and read the entire array */
int *arr = malloc (w * h * sizeof (int));
for (i = 0; i < w * h; ++i)
scanf ("%d", &arr[i]);
/* Obtain a shared memory segment with the key 42 */
int shm = shmget (42, h * sizeof (int), IPC_CREAT | 0666);
if (shm < 0)
{
perror ("shmget");
return 1;
}
/* Attach the segment as an int array */
int *row = shmat (shm, NULL, 0);
if (row < (int *) NULL)
{
perror ("shmat");
return 1;
}
for (i = 0; i < h; ++i)
/* Create h children and make them work */
if (!fork ())
{
for (j = row[i] = 0; j < w; ++j)
row[i] += arr[i * w + j];
return 0;
}
/* Wait for the children to finish up */
for (i = 0; i < h; ++i)
wait (&j);
/* Sum the row totals */
for (i = j = 0; i < h; ++i)
j += row[i];
printf ("%d\n", j);
/* Detach the shared memory segment and delete its key for later reuse */
shmdt (row);
shmctl (shm, IPC_RMID, NULL);
free (arr);
return 0;
}
Upvotes: 1