I am trying to determine whether an element exits in a vector using N processes and if true, return all its positions. Each process receives an index and a step. The index is from 0 to "numberOFProcesses -1" and each process check element starting from index, incremented by step.
How it works: Let us assume we have 4 processes. Process 0 checks elements 0,4,8..., process 1 checks 1,5,9... etc.
How did I implement this: I got 2 pipes: one pipes is used for positions; the second pipe is to store the number of occurrences of the target. Whenever a process find the target it increments the number of occurrences and writes the index to the "index" pipe and, finally, upon exiting job, it writes to "occurrences" pipe the number of occurrences, if any, and return true or false. I initially wanted to directly return the number of occurrences but I realized that "WEXITSTATUS" uses only 8 bits and that might be an issue.
The problem: Attempting to read a chunk of size "occurrences" fails or gives invalid results. Reading a value at a time seems to work fine. I have also checked it using valgrind and gdb, but I cannot seem to find the problem. Valgrind reports a ton of issues when attempting to read the chunk, but 0 errors when reading one at time. The reading of occurrences is done only if the process has found the target.
P.S. I know I can leave it like that, but it wouldn't make sense reading multiple times.
Now, for some code:
#include <stdio.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <wait.h>
#include <sys/signal.h>
#include <sys/types.h>
/**
* #brief basic defines
*
*/
#define MAX_RAND 100
#define TRUE 1
#define FALSE 0
#define CHILDREN 0
#define READ 0
#define WRITE 1
int size = 13;
int *array;
int target;
int index_pipe[2];
int occurences_pipe[2];
/**
* #brief this populates the array with random number
*
* #param array the given array
* #param size the size of the array
*/
void populate(int *array, int size)
{
for (int i = 0; i < size; i++)
{
array[i] = rand() % MAX_RAND;
}
}
/**
* #brief this determines whether an elements occurs in an array and writes to pipes the number
* of occurences and the the indexes on which resides the target
*
* #param target the value we are looking for
* #param index the index of the process, i.e. the process id
* #param step the step, i.e. the number of processes
* #return int the search status. This returns true if "target occurs", FALSE otherwise
*/
int search(int target, int index, int step)
{
int i = index;
int numberOfOccurences = 0;
/**
* #brief each process will start at position index and will check values starting with index, incrementing with step
* ex: process 0 will check 0,4,8,12..
* process 1 will check 1,5,9,13...
*/
while (i < size)
{
if (target == array[i])
{
/**
* #brief if the target occues increment the number of occurences and write an index to pipe
*
*/
numberOfOccurences++;
write(index_pipe[WRITE], &i, sizeof(int));
}
i += step;
}
/**
* #brief write occurences to pipe if, and only if, the number of occurences is not 0,
* i.e. we have found the target at least once and return TRUE or FALSE
*
*/
if (numberOfOccurences != 0)
{
write(occurences_pipe[WRITE], &numberOfOccurences, sizeof(int));
return TRUE;
}
return FALSE;
}
/**
* #brief this prints a given array
*
* #param array the array we want to print
* #param size the size of the array
*/
void printArray(int *array, int size)
{
printf("Array: \n");
for (int i = 0; i < size; i++)
{
printf("%d ", array[i]);
}
printf("\n");
}
/**
* #brief entry point
*
* #return int EXIT_SUCCESS
*/
int main()
{
/**
* #brief initialize and allocate memory
*
*/
size = 13;
array = (int *)malloc(sizeof(int) * size);
pipe(index_pipe);
pipe(occurences_pipe);
int numerOfProccesses = 3;
int target = 15;
int totalOccurences = 0;
int status = -1;
int exit_status = -1;
int occurences = -1;
populate(array, size);
array[size - 1] = target;
printArray(array, size);
size_t processes[numerOfProccesses];
/**
* #brief create childrens and put them to work
*
*/
for (int i = 0; i < numerOfProccesses; i++)
{
processes[i] = fork();
if (CHILDREN == processes[i])
{
/**
* #brief get the search status and exit
*
*/
int exit_status = search(target, i, numerOfProccesses);
exit(exit_status);
}
}
/**
* #brief wait for children to exit
*
*/
for (int i = 0; i < numerOfProccesses; i++)
{
/**
* #brief wait for each children. If a children is done AND it has found taget, i.e. returned TRUE,
* then read the number of occurrences from pipe
*
*/
wait(&status);
if (WIFEXITED(status))
{
exit_status = WEXITSTATUS(status);
if (exit_status == TRUE)
{
read(occurences_pipe[READ], &occurences, sizeof(int));
totalOccurences += occurences;
}
}
}
/**
* #brief if the number of occurrences is 0, then we have'nt found target
*
*/
if (totalOccurences == 0)
{
printf("%d not found \n", target);
}
else
{
/**
* #brief else allocate memory for an array of size "occurrences" and read from index pipe
*
*/
printf("Found %d on %d positions\n", target, totalOccurences);
int *indexes = (int *)malloc(sizeof(int) * 3);
// for (int i = 0; i < totalOccurences; i++)
// {
// int value;
// read(index_pipe[READ], &value, sizeof(int));
// printf("Read %d \n", value);
// }
int pipe_status;
pipe_status = read(index_pipe[READ], indexes, totalOccurences);
printf("Pipe read %d bytes\n", pipe_status);
printArray(indexes, totalOccurences);
}
return 0;
}
Expected output:
Array:
83 86 77 15 93 35 86 92 49 21 62 27 15
Found 15 on 2 positions
Read 3
Read 12
Array:
3 12
I get this when reading a chunk at a time:
Array:
83 86 77 15 93 35 86 92 49 21 62 27 15
Found 15 on 2 positions
Pipe read 2 bytes
Array:
3 0
P.S. I wrote this on a linux machine. I compiled this using: gcc -g -o search search.c -Wextra
...
read(occurences_pipe[READ], &occurences, sizeof(int));
totalOccurences += occurences;
int *indexes = (int *)malloc(sizeof(int) * 3);
read(index_pipe[READ], indexes, totalOccurences);
Well, you are reading an unknown number of bytes, which is the sum of occurences of the numbers found within each process from the pipe and saving it into sizeof(int) * 3 bytes, which can possibly overflow. Also the totalOccurences is the sum from all the processes. I think you meant to:
int *indexes = (int *)malloc(sizeof(int) * totalOccurences);
read(index_pipe[READ], indexes, sizeof(int) * totalOccurences);
I like this idea of concurency and single pipes to communicate with multiple processes. You can speed things up a bit, by using realloc + read(index_pipe[READ], ..., sizeof(int) * occurences) right in the reading if (exit_status == TRUE) loop. That way you could earlier free the data buffered in pipe.
I don't think there is the need for occurences_pipe if you are just interested in the sum of all occurences. You can just set O_NONBLOCK on the index_pipe[READ], and read from it byte by byte (or chunk by chunk) until all threads will finish and the read will return 0. The sum of all occurences is the number of bytes read from index_pipe after all threads exited divided by sizeof(int).
I think that threads would be better suited for such task, you are copying the whole array between processes on fork, when using pthreads each thread would use the same memory.
And, for the love of K&R, don't cast the result of malloc.
Related
When I test my program with large vectors, as in larger than 12 elements, it crashes (I get an lldb error). However, it works fine for small vectors. I think it's trying to access a memory space it shouldn't, but I have no idea how to fix it.
The program is supposed to print out the vectors whose sum of elements are equal to the "target"
Also, is there a different way that I can express: if (i & (1 << j)) ?
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int c = 0;
/* find subsets of a given set */
void findSubsets(int *value, int n, int i) {
int j;
if (i < 0)
return;
for (j = 0; j < n; j++) {
/*
* checking jth bit is set in i. If
* it is set, then fetch the element at
* jth index in value array
*/
if (i & (1 << j)) {
suma = suma + value[j];
}
/* recursive call */
findSubsets(value, n, i - 1);
return;
}
int main() {
/* 2^n - indicates the possible no of subsets */
int count = pow(2, size);
/* finds the subsets of the given set */
findSubsets(vector, size, count - 1);
return 0;
}
I would like to be able to use this program for large vectors (up to about 20)
The problem is that you got 52428810 recursive function calls. This will cause a stack overflow. Instead of recursion, try iteration:
for (int i = 0; i < count; i++) {
findSubsets(vector, size, i);
}
And remove the recursive call within findSubsets.
I have two questions.
First:
I need to create thread blocks gradually not more then some max value, for example 20.
For example, first 20 thread go, job is finished, only then 20 second thread go, and so on in a loop.
Total number of jobs could be much larger then total number of threads (in our example 20), but total number of threads should not be bigger then our max value (in our example 20).
Second:
Could threads be added continuously? For example, 20 threads go, one thread job is finished, we see that total number of threads is 19 but our max value is 20, so we can create one more thread, and one more thread go :)
So we don't waste a time waiting another threads job to be done and our total threads number is not bigger then our some max value (20 in our example) - sounds cool.
Conclusion:
For total speed I consider the second variant would be much faster and better, and I would be very graceful if you help me with this, but also tell how to do the first variant.
Here is me code (it's not working properly and the result is strange - some_array elements become wrong after eleven step in a loop, something like this: Thread counter = 32748):
#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <math.h>
#define num_threads 5 /* total max number of threads */
#define lines 17 /* total jobs to be done */
/* args for thread start function */
typedef struct {
int *words;
} args_struct;
/* thread start function */
void *thread_create(void *args) {
args_struct *actual_args = args;
printf("Thread counter = %d\n", *actual_args->words);
free(actual_args);
}
/* main function */
int main(int argc, char argv[]) {
float block;
int i = 0;
int j = 0;
int g;
int result_code;
int *ptr[num_threads];
int some_array[lines] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17};
pthread_t threads[num_threads];
/* counting how many block we need */
block = ceilf(lines / (double)num_threads);
printf("blocks= %f\n", block);
/* doing ech thread block continuously */
for (g = 1; g <= block; g++) {
//for (i; i < num_threads; ++i) { i < (num_threads * g),
printf("g = %d\n", g);
for (i; i < lines; ++i) {
printf("i= %d\n", i);
/* locate memory to args */
args_struct *args = malloc(sizeof *args);
args->words = &some_array[i];
if(pthread_create(&threads[i], NULL, thread_create, args)) {
free(args);
/* goto error_handler */
}
}
/* wait for each thread to complete */
for (j; j < lines; ++j) {
printf("j= %d\n", j);
result_code = pthread_join(threads[j], (void**)&(ptr[j]));
assert(0 == result_code);
}
}
return 0;
}
I'm writting a program that needs to pass a matrix from a parent process to its child (that's why I'm using the fork() instruction). I've just read this and this to solve the problem myself, but I still can't understand how to use the read() and write() instructions with the pipe I've created so far. I know these instructions write series of bytes, but I'm not sure about using them with structures or dynamically allocated variables (like a matrix).
Here is the code I used to test (note the comments I put):
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
// Structure definition (Matrix)
typedef struct {
int **mat;
int rows;
int cols;
} Matrix;
int main() {
// Create the pipe
int file_desc[2];
if (pipe(file_desc) != 0) exit(1);
// Create two processes
if (fork() == 0) {
/** Instructions for the child process */
// Read the matrix structure from the pipe
Matrix *received = NULL;
read(file_desc[0], received, sizeof *received);
if (received != NULL) {
// Print the received matrix
int i, j;
printf("The matrix I've just *received* from the parent is:\n");
for (i = 0; i < received->cols; i++) {
for (j = 0; j < received->rows; j++) printf("%d\t", received->mat[i][j]);
printf("\n");
}
} else printf("received = NULL :'(\n");
} else {
/** Instructions for the parent process */
/* Create a matrix dinamically.
* In fact, in the real program I have a function to create a matrix given the
* rows and columns, and fill it with random values, so it returns a Matrix *
* (pointer to Matrix), but for testing purposes I've only written this
* (also useful if I need an array of Matrix elements, for example)
* */
Matrix *myMatrix = calloc(1, sizeof *myMatrix);
// Put the contents into the variable
myMatrix->rows = 2;
myMatrix->cols = 2;
myMatrix->mat = calloc(myMatrix->rows, sizeof *(myMatrix->mat));
int i, j;
for (i = 0; i < myMatrix->cols; i++)
(myMatrix->mat)[i] = calloc(myMatrix->cols, sizeof **(myMatrix->mat));
// Fill the matrix with some values (testing)
(myMatrix->mat)[0][0] = 4;
(myMatrix->mat)[0][1] = 2;
(myMatrix->mat)[1][0] = 1;
(myMatrix->mat)[1][1] = 3;
// Print the matrix
printf("The matrix I've just filled in the parent is:\n");
for (i = 0; i < myMatrix->cols; i++) {
for (j = 0; j < myMatrix->rows; j++) printf("%d\t", myMatrix->mat[i][j]);
printf("\n");
}
// Write the matrix structure to the pipe (here is where I have the problem!)
write(file_desc[1], myMatrix, sizeof *myMatrix);
// Wait for the child process to terminate
wait(0);
printf("The child process has just finished, the parent process continues.\n");
}
return 0;
}
In fact, I tried first with a pointer to an int and it worked. But when I run this program, I receive this output:
The matrix I've just filled in the parent is:
4 2
1 3
received = NULL :'(
The child process has just finished, the parent process continues.
And I don't know why I get the NULL -- I'm almost sure I'm using the write() instruction incorrectly. Any help about this will be appreciated =)
EDIT: I think the matrix should be converted to text, for example, and then pass the string to the child, parse it and convert it to a Matrix structure again. I don't know if this approach is the best. Is there another approach besides this one?
EDIT: I tried the same code with a static variable (changing int **mat; to int mat[2][2]; inside the structure declaration) but the user should change the matrix size.
This is a serious problem:
Matrix *received = NULL;
read(file_desc[0], received, sizeof *received);
Received is a null pointer. That read is going to try to write data to NULL, which is an invalid address. It would be much simpler to write:
Matrix received;
read(file_desc[0], &received, sizeof received);
I've been at this problem for like 3 days and I've combed my entire code to try to figure out why I'm getting incorrect output. The purpose of this program is to do a merge sort using threads. The first part is simply sorting the elements in parallel into however many segments a user inputs. The only inputs tested will be 2, 5, and 10. And the array to be sorted will always be 50 int array of randomly generated numbers.My code works fine when the segments entered (denoted by the variable 'segments' at the top of main) is 2. However, when I change segments to 5 or 10, I don't get a sorted array at the end. I've tried debugging by using print statements (which I've commented out but you can still see) and there seems to be a problem during the first two merge iterations. For some reason the resulting of those merge iterations are not in order, and they contain duplicate numbers that don't exist in duplicate in the original array passed to it. My sorting method and merging methods work fine when I just pass arrays to them, and don't use threads but when I do use threads I get behavior that I can't explain. Below is my program in its entirety, to merge an array of 50 it should do the following:
split the array into 10 segments of 5, and sort each segment.
pass the segments in pairs, in rounds. So round one should pas segment 0-5 in one segment and 5-10 in another, 10-15 and 15-20, 20-25 and 25-30, and so on until it reaches 40-45 and 45-50.
then it will go into round two which does same thing as round one but it passes the segments in pairs of 10. So 0-10 and 10-20, 20-30 and 30-40, then it leaves the last part of 10 untouched
round three passes the segments to merge in pairs of 20: 0-20 and 20-40, then stops.
Finally it should merge the segments 0-40 with 40-50.
My program: (you should mainly focus on my main function, sort is fine, and merge seems fine too, but i've included them anyways just in case)
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <pthread.h>
/**
* Struct to contain an array partition as well as the size of the partition.
* Use struct to pass multiple parameters to pthread_create
*/
struct array_struct{
int *partition;
int size;
};
/**
* Struct that contains two arrays (should be sorted) to merge
* Use struct to pass multiple parameters to pthread_create
*/
struct arrays_to_merge{
int *array1;
int *array2;
int size1;
int size2;
};
//comparison function to use with qsort, sorts in ascending order
int cmpfunc (const void * a, const void * b)
{
return ( *(int*)a - *(int*)b );
}
/**
* Method that takes a struct containing a pointer to the first int in an array
* partition, as well as the partition size. Object must be type void, used with pthread_create
* #param pointer to the partition object. Type void
*/
void *sort(void *object){
struct array_struct *structure;
structure = (struct array_struct *) object;
int *array = structure->partition;
int size = structure->size;
int *i, j = 0;
qsort(array, size, sizeof(int), cmpfunc);
printf("Sorted %d elements.\n", size);
}
void *merge(void * object){
struct arrays_to_merge *arrays_struct;
arrays_struct = (struct arrays_to_merge *) object;
int *array1 = arrays_struct->array1;
int *array2 = arrays_struct->array2;
int size1 = arrays_struct->size1;
int size2 = arrays_struct->size2;
int tempArray[size1 + size2];
int i = 0, j = 0, k = 0, duplicates = 0;
while (i < size1 && j < size2) {
// printf("Merge number : %d Comparing %d and %d\n", mergenumber, array1[i], array2[j]);
if (array1[i] <= array2[j]) {
// printf("Picking %d\n", array1[i]);
tempArray[k] = array1[i];
if (array1[i] == array2[j])
{
duplicates++;
}
i++;
k++;
}else {
// printf("Merge number : %d Picking %d\n", mergenumber, array2[j]);
tempArray[k] = array2[j];
k++;
j++;
}
}
while (i < size1) {
// printf("Merge number : %d left over Picking %d\n", mergenumber, array1[i]);
tempArray[k] = array1[i];
i++;
k++;
}
while (j < size2) {
// printf("Merge number : %d left over Picking %d\n", mergenumber, array2[j]);
tempArray[k] = array2[j];
k++;
j++;
}
array1 = arrays_struct->array1;
for(i = 0; i < size1 + size2; i++){
array1[i] = tempArray[i];
}
printf("Merged %d and %d elements with %d duplicates\n", size1, size2, duplicates);
}
//return an array of size 50 with randomly generated integers
int *randomArray(){
srand(time(NULL));
static int array[50];
int i;
for (i = 0; i < 50; ++i){
array[i] = rand() % 51;
}
return array;
}
int main(int argc, char const *argv[])
{
int segments = 10;//make equal to argv input after testing
pthread_t threads[segments];
int i, *numbers; //iterator i, and pointer to int array 'numbers'
numbers = randomArray(); //return an array of random ints and store in 'numbers'
struct array_struct array[segments];
for(i = 0; i < segments; i++){
int *partition = numbers + (i * (50/segments));//obtain the first index of partition
array[i].partition = partition;
array[i].size = 50/segments;
pthread_create(&threads[i], NULL, sort, (void *) &array[i]);
}
for(i = 0; i < segments; i++){
pthread_join(threads[i], NULL);
}
int count = segments;
struct arrays_to_merge arrays[segments];
int j;
int size = 50/ segments;
while(count > 1){
for(i = 0, j = 0; i < count-1; j++, i += 2){
int *partition = numbers + (i * (size));
int *partition2 = numbers + (i+1 * (size));
arrays[j].array1 = partition;
arrays[j].array2 = partition2;
arrays[j].size1 = size;
arrays[j].size2 = size;
pthread_create(&threads[j], NULL, merge, (void *) &arrays[j]);
}
for(i = 0; i < j; i++){
pthread_join(threads[i], NULL);
}
size = size * 2;
count = count/2;
}
if(segments != 2){//for segments = 2, no need for his
int *partition = numbers;
int *partition2 = numbers + (size);
arrays[0].array1 = partition;
arrays[0].array2 = partition2;
arrays[0].size1 = size;
arrays[0].size2 = 50 - size;
pthread_create(&threads[0], NULL, merge, (void *) &arrays[0]);
pthread_join(threads[0], NULL);
}
for(i = 0; i < 50; i++){
printf("%d\n", numbers[i]);
}
pthread_exit(NULL);
return 0;
}
this is my output:
Sorted 5 elements.
Sorted 5 elements.
Sorted 5 elements.
Sorted 5 elements.
Sorted 5 elements.
Sorted 5 elements.
Sorted 5 elements.
Sorted 5 elements.
Sorted 5 elements.
Sorted 5 elements.
Merged 5 and 5 elements with 0 duplicates
Merged 5 and 5 elements with 0 duplicates
Merged 5 and 5 elements with 0 duplicates
Merged 5 and 5 elements with 0 duplicates
Merged 5 and 5 elements with 0 duplicates
Merged 10 and 10 elements with 3 duplicates
Merged 10 and 10 elements with 1 duplicates
Merged 20 and 20 elements with 7 duplicates
Merged 40 and 10 elements with 17 duplicates
0
6
9
11
12
13
13
14
15
17
19
23
25
25
25
26
26
28
28
28
28
30
32
32
32
34
39
41
41
44
44
44
44
44
50
50
9
15
50
9
15
19
26
50
50
9
15
11
14
50
Sorry for the long wall of text, I've tried resolving this on my own and after countless hairs pulled I can't figure it out. Please help me figure out what I'm doing wrong. I think my problem lies in either the way I'm joining threads, or my merge function but since I cant be sure, i just included the whole thing.
It took a while but finally I got there :)
The problem is with this line:
int *partition2 = numbers + (i+1 * (size));
which is equivalent to (due to operator precedence).
int *partition2 = numbers + (i + size);
and is not what you want.
It should be:
int *partition2 = numbers + ((i+1) * (size));
Notice the additional brackets. Without which, the partition2 index is calculated incorrectly. Hence, merging with different parts of the array.
For a project of mine, I am required to pass matrices (which, later on will be of various sizes determined at run-time) between processes, and perform operations on them. This will be performed on a UNIX system.
While teaching myself about fork() and pipe(), I managed to establish two one-way pipes between the processes (one from parent to child and vice versa) to some extent.
===========================================================
Here is my code:
#include <sys/types.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#define READ_END 0
#define WRITE_END 1
#define MATRIX_N 2
void print_mat(int**, int);
int main(void){
// INITIALIZE
int **w_mat, **r_mat, **return_mat, i, j;
int fd1[2];
int fd2[2];
pid_t pid;
// Allocate memory for respective arrays
w_mat = (int**) malloc(sizeof(int *) * MATRIX_N);
for( i = 0 ; i < MATRIX_N ; i++ ){
*(w_mat + i) = (int*) malloc (sizeof(int *) * MATRIX_N);
}
r_mat = (int**) malloc(sizeof(int *) * MATRIX_N);
for( i = 0 ; i < MATRIX_N ; i++ ){
*(r_mat + i) = (int*) malloc (sizeof(int *) * MATRIX_N);
}
return_mat = (int**) malloc(sizeof(int *) * MATRIX_N);
for( i = 0 ; i < MATRIX_N ; i++ ){
*(return_mat + i) = (int*) malloc (sizeof(int *) * MATRIX_N);
}
// Assign initial values to matrix for writing
w_mat[0][0] = 2;
w_mat[0][1] = 7;
w_mat[1][0] = 12;
w_mat[1][1] = 9;
// Initialize and check pipes respectively
if( pipe(fd1) == -1){
fprintf(stderr, "Pipe failed");
return 1;
}
if( pipe(fd2) == -1){
fprintf(stderr, "Pipe failed");
return 1;
}
// Fork a child, then check it
pid = fork();
if( pid < 0 ){
fprintf(stderr, "Fork failed");
}
if( pid > 0 ){ /* PARENT */
// Close unnecessary pipe ends
close(fd1[READ_END]);
close(fd2[WRITE_END]);
printf("\nMatrix to send to child: ");
print_mat(w_mat, MATRIX_N);
// Write to pipe 1, matrix for child, then close pipe
write(fd1[WRITE_END], w_mat, MATRIX_N * MATRIX_N * sizeof(int*));
// Wait for child to process values, write, and terminate
wait(NULL);
// Read values from pipe 2
read(fd2[READ_END], return_mat, MATRIX_N * MATRIX_N * sizeof(int*));
printf("\nDoubled matrix received from child: ");
print_mat(return_mat, MATRIX_N);
// Close used pipe ends
close(fd2[READ_END]);
close(fd1[WRITE_END]);
}else{ /* CHILD */
// Close unnecessary pipe ends
close(fd1[WRITE_END]);
close(fd2[READ_END]);
// Read from pipe 1 the matrix from the parent
read(fd1[READ_END], r_mat, MATRIX_N * MATRIX_N * sizeof(int*));
printf("\nReceived matrix from parent to double: ");
print_mat(r_mat, MATRIX_N);
// Double the values in the matrix from parent
for( i = 0 ; i < MATRIX_N ; i++ ){
for( j = 0 ; j < MATRIX_N ; j++){
r_mat[i][j] = r_mat[i][j] * MATRIX_N;
}
}
printf("\nDoubled matrix to send to parent: ");
print_mat(r_mat, MATRIX_N);
// Write to pipe 2, the doubled matrix to be received by parent
write(fd2[WRITE_END], r_mat, MATRIX_N * MATRIX_N * sizeof(int*));
// Close used pipe ends
close(fd2[WRITE_END]);
close(fd1[READ_END]);
}
// Terminate
return 0;
}
===========================================================
The problem arises when running the program:
===========================================================
Matrix to send to child:
| 2 7 |
| 12 9 |
Received matrix from parent to double:
| 2 7 |
| 12 9 |
Doubled matrix to send to parent:
| 4 14 |
| 24 18 |
Doubled matrix received from child:
| 2 7 |
| 12 9 |
===========================================================
The array before writing is correct, and it seems as if somehow in the midst of writing it to pipe 2 from the child and reading it back in from said pipe once the child terminates; the values return to what they were. I don't believe it could be either process tampering with it, as each has its own variable array to store the data, and aside from the pipes there is really no instance where, in the if-statement of my program, either process directly affects the array of another--To the best of my knowledge, that is.
Could there, in fact, be an instance in which the parent or child indirectly affects the written and read arrays which I am not considering? If so, how could I keep this in check? If not, where exactly did I go wrong? Was my pipe implementation inherently flawed? I'm not really sure what to look for.
Also; in the far-left of field instance that my matrix printing function is the culprit, here is that:
void print_mat(int** a, int n){
int i, j;
for( i = 0 ; i < n ; i++){
printf("\n| ");
for( j = 0 ; j < n ; j++){
printf("%d", a[i][j]);
if( j != n - 1){
printf(" ");
}
}
printf(" |\n");
}
}
Each matrix is an array of pointers, where each pointer points to an array of ints. Therefore the method that you are using to pass the matrix between the parent and child won't work the way you want it to.
What you are doing is passing four pointers across the pipe (of which only the first two are valid). Since the child is a carbon copy of the parent, those pointers do in fact point to the original matrix in the parent's address space. Therefore, the parent prints the original matrix.
What you want to do is pass the integer values across the pipe and reconstruct the matrix on the other side. Code similar to the print_mat function is needed to write the individual values into the pipe. On the receiving side, those values need to be read and stored at the proper locations in the array.
Let me see if I can clarify with an example. If the array was declared as
int w_mat[2][2];
then you could transfer the entire array like this
write(fd1[WRITE_END], w_mat, 2*2 * sizeof(int) );
But in fact the array is equivalent to this
int *w_mat[2];
w_mat[0] = malloc( 2 * sizeof(int) );
w_mat[1] = malloc( 2 * sizeof(int) );
Therefore, the line
write(fd1[WRITE_END], w_mat, MATRIX_N * MATRIX_N * sizeof(int*));
is writing four int * to the pipe. That's bad for two reasons.
The array only has two pointers in it
Passing pointers across the pipe is not the same as sending the data across the pipe.