Multiple processes with pipe, unexpected variable change? - c

I know it sounds unreal "unexpected variable change." Since I couldn't spot the problem I used that title...
Firstly, this is my homework. The homework is about reading two matrices from file then create 4 child processes, parent will send (via pipe) the quarter pieces of matrix to child processes. Child process will make their calculations afterwards they will send the calculated indices back to parent process(via pipe again. Trying to achieve bidirectional pipes here.) so parent will print calculated values to stdout and return.
Currently what I have done is read those matrices from file, created 3 processes(was going step by step), send 1/4 of matrices to each 3 processes and tried to check if i succeeded or not.
The problem is "generally" what happens is either I see third_start variable is changed (in the same scope) therefore it doesn't even enter the loop.
Also I observed couple more things;
When redirecting the output to some file the data is looks like %10 of my program written there.
If I supply the matrix with smaller values like 4x4 matrices. The problem with third_start doesn't happen.
I'm sure that I'm doing something stupid.
Here is related part of my code. (Bit messy, it's not the way I send my homeworks.. Please ignore the calculations about matrices.)
int pipe_fds[2]; //first pipe
int pipe_fds2[2];//second pipe
int pipe_fds3[2];//third pipe
int pipe_fds4[2];//fourth pipe
int pip_ret, pip_ret2, pip_ret3, pip_ret4;
int pid2,pid3,pid4,pid5; //assumed p1 is parent and 2,3,4,5 are child processes.
int single_x; //store single_x val;
int single_y;
pip_ret = pipe(pipe_fds);
pid2 = fork();
if(pip_ret == -1)
{
fprintf(stderr, "%s\n", "Unable to create pipe\n");
exit(1);
}
else if(pid2 == 0)
{
if (close(pipe_fds[1]) == -1)
{
perror("close");
exit(EXIT_FAILURE);
}
int first_quarter_x[_pow(2, n) / 2][_pow(2, n) / 2];
int first_quarter_y[_pow(2, n) / 2][_pow(2, n) / 2];
for(i = 0 ; i < _pow(2, n) / 2 ; ++i)
{
for(j = 0 ; j < _pow(2, n) / 2; ++j)
{
if(read(pipe_fds[0], &single_x, sizeof(single_x)) <= 0)
{
perror("read failed ");
exit(EXIT_FAILURE);
}
first_quarter_x[i][j] = single_x;
if(read(pipe_fds[0], &single_y, sizeof(single_y)) <= 0)
{
perror("read failed ");
exit(EXIT_FAILURE);
}
first_quarter_y[i][j] = single_y;
fprintf(stderr,"(2)Child with pid %d received value %d\n",getpid(), single_x);
fprintf(stderr,"(2)Child with pid %d received value %d\n",getpid(), single_y);
}
}
for(i = 0 ; i < _pow(2, n) / 2 ; ++i)
{
for(j = 0 ; j < _pow(2, n) / 2; ++j)
{
if(matrixA[i][j] == first_quarter_x[i][j])
{
fprintf(stderr,"Good2a\n" );
}
else
{
fprintf(stderr,"Bad2a.\n" );
}
}
fprintf(stderr,"\n" );
}
for(i = 0 ; i < _pow(2, n) / 2 ; ++i)
{
for(j = 0 ; j < _pow(2, n) / 2; ++j)
{
if(matrixB[i][j] == first_quarter_y[i][j])
{
printf("Good2b\n" );
}
else
{
printf("Bad2b.\n" );
}
}
fprintf(stderr,"\n" );
}
exit(EXIT_SUCCESS);
}
pip_ret2 = pipe(pipe_fds2);
pid3 = fork();
if(pip_ret2 == -1)
{
fprintf(stderr, "%s\n", "Unable to create pipe for 3.process\n");
exit(1);
}
else if(pid3 == 0)
{
if (close(pipe_fds2[1]) == -1)
{
perror("close");
exit(EXIT_FAILURE);
}
int second_start = _pow(2, n) / 2;
int second_quarter_x[_pow(2, n) / 2][_pow(2, n) / 2];
int second_quarter_y[_pow(2, n) / 2][_pow(2, n) / 2];
for(i = 0 ; i < _pow(2, n) / 2 ; ++i)
{
for(j = second_start ; j < _pow(2, n); ++j)
{
if(read(pipe_fds2[0], &single_x, sizeof(single_x)) <= 0)
{
perror("read failed ");
exit(EXIT_FAILURE);
}
second_quarter_x[i][j] = single_x;
if(read(pipe_fds2[0], &single_y, sizeof(single_y)) <= 0)
{
perror("read failed ");
exit(EXIT_FAILURE);
}
second_quarter_y[i][j] = single_y;
fprintf(stderr,"(3)Child with pid %d received value %d\n",getpid(), single_x);
fprintf(stderr,"(3)Child with pid %d received value %d\n",getpid(), single_y);
}
}
for(i = 0 ; i < _pow(2, n) / 2 ; ++i)
{
for(j = second_start ; j < _pow(2, n) ; ++j)
{
if(second_quarter_x[i][j] == matrixA[i][j])
{
fprintf(stderr,"Good3a \n" );
}
else
{
fprintf(stderr,"Bad3a\n" );
}
}
fprintf(stderr,"\n" );
}
for(i = 0 ; i < _pow(2, n) / 2 ; ++i)
{
for(j = second_start ; j < _pow(2, n) ; ++j)
{
if(second_quarter_y[i][j] == matrixB[i][j])
{
fprintf(stderr,"Good3b \n" );
}
else
{
fprintf(stderr,"Bad3b\n" );
}
}
fprintf(stderr,"\n" );
}
exit(EXIT_SUCCESS);
}
pip_ret3 = pipe(pipe_fds3);
pid4 = fork();
if(pip_ret3 == -1)
{
fprintf(stderr, "%s\n", "Unable to create pipe for 4.process\n");
exit(1);
}
else if(pid4 == 0)
{
if (close(pipe_fds3[1]) == -1)
{
perror("close");
exit(EXIT_FAILURE);
}
int third_start = _pow(2, n) / 2;
printf("THIRD START IS %d\n",third_start ); //here it prints normal.
int third_quarter_x[_pow(2, n) / 2][_pow(2, n) / 2];
int third_quarter_y[_pow(2, n) / 2][_pow(2, n) / 2];
for(i = third_start ; i < _pow(2, n) ; ++i)
{
for(j = 0 ; j < _pow(2, n) / 2; ++j)
{
if(read(pipe_fds3[0], &single_x, sizeof(single_x)) <= 0)
{
perror("read failed ");
exit(EXIT_FAILURE);
}
third_quarter_x[i][j] = single_x;
if(read(pipe_fds3[0], &single_y, sizeof(single_y)) <= 0)
{
perror("read failed ");
exit(EXIT_FAILURE);
}
third_quarter_y[i][j] = single_y;
fprintf(stderr,"(4)Child with pid %d received value %d\n",getpid(), single_x);
fprintf(stderr,"(4)Child with pid %d received value %d\n",getpid(), single_y);
}
}
printf("THIRD START IS %d\n",third_start ); //then it prints something anormal...
for(i = third_start ; i < _pow(2, n) ; ++i)
{
for(j = 0 ; j < _pow(2, n) / 2; ++j)
{
if(third_quarter_x[i][j] == matrixA[i][j])
{
fprintf(stderr,"Good4a \n" );
}
else
{
fprintf(stderr,"Bad4a\n" );
}
}
printf("\n" );
}
for(i = third_start ; i < _pow(2, n) ; ++i)
{
for(j = 0 ; j < _pow(2, n) / 2; ++j)
{
if(third_quarter_x[i][j] == matrixB[i][j])
{
fprintf(stderr,"Good4b \n" );
}
else
{
fprintf(stderr,"Bad4b\n" );
}
}
fprintf(stderr,"\n" );
}
exit(EXIT_SUCCESS);
}
//parent start
if (close(pipe_fds[0]) == -1)
{
perror("close");
exit(EXIT_FAILURE);
}
fprintf(stderr,"First quarter beginning \n");
for(i = 0 ; i < _pow(2, n) / 2 ; ++i)
{
for(j = 0 ; j < _pow(2, n) / 2; ++j)
{
single_x = matrixA[i][j];
single_y = matrixB[i][j];
write(pipe_fds[1], &single_x, sizeof(single_x));
write(pipe_fds[1], &single_y, sizeof(single_y));
fprintf(stderr,"Parent with pid %d sent value to 2 %d\n",getpid(), single_x);
fprintf(stderr,"Parent with pid %d sent value to 2 %d\n",getpid(), single_y);
}
}
wait(NULL);
fprintf(stderr,"First quarter end\n \n");
fprintf(stderr,"Second quarter beginning\n");
if (close(pipe_fds2[0]) == -1)
{
perror("close");
exit(EXIT_FAILURE);
}
int sec = _pow(2,n) / 2;
for(i = 0 ; i < _pow(2, n) / 2 ; ++i)
{
for(j = sec ; j < _pow(2, n); ++j)
{
single_x = matrixA[i][j];
single_y = matrixB[i][j];
write(pipe_fds2[1], &single_x, sizeof(single_x));
write(pipe_fds2[1], &single_y, sizeof(single_y));
fprintf(stderr,"Parent with pid %d sent value to 3 %d\n",getpid(), single_x);
fprintf(stderr,"Parent with pid %d sent value to 3 %d\n",getpid(), single_y);
}
}
wait(NULL);
fprintf(stderr,"Second quarter end\n");
fprintf(stderr,"Third quarter beginning\n");
if (close(pipe_fds3[0]) == -1)
{
perror("close");
exit(EXIT_FAILURE);
}
int third = _pow(2,n) / 2;
for(i = third ; i < _pow(2, n) ; ++i)
{
for(j = 0 ; j < _pow(2, n) / 2; ++j)
{
single_x = matrixA[i][j];
single_y = matrixB[i][j];
write(pipe_fds3[1], &single_x, sizeof(single_x));
write(pipe_fds3[1], &single_y, sizeof(single_y));
fprintf(stderr,"Parent with pid %d sent value to 4 %d\n",getpid(), single_x);
fprintf(stderr,"Parent with pid %d sent value to 4 %d\n",getpid(), single_y);
}
}
wait(NULL);
fprintf(stderr,"Third quarter end\n");

int pipe_fds2[2];//second pipe
Indirect help: numbered variables are almost always better represented as arrays. You probably want an array of structures
struct child_t {
int datapipe[2], resultpipe[2];
pid_t pid;
int result;
} children[4];
Now you can iterate over your array, and for each element call pipe and fork. Each child deals only with its pipe, but the parent can iterate over all children. In a matrix, I imagine it matters which part of the matrix produces which result, and this structure would keep those pieces of information related.
By organizing your data that way, you eliminate the temptation to duplicate code, because a loop on an array is easier. Less code means fewer bugs, so you get your homework done sooner.

You're accessing outside the arrays.
int third_start = _pow(2, n) / 2;
printf("THIRD START IS %d\n",third_start ); //here it prints normal.
int third_quarter_x[_pow(2, n) / 2][_pow(2, n) / 2];
int third_quarter_y[_pow(2, n) / 2][_pow(2, n) / 2];
The indexes of both dimensions of third_quarter_x and third_quarter_y go from 0 to third_start-1. But then you have the following loops:
for(i = third_start ; i < _pow(2, n) ; ++i)
{
for(j = 0 ; j < _pow(2, n) / 2; ++j)
{
The values of i are outside the range of indexes for the first dimension. Since you're writing outside the array, you're causing undefined behavior.
The loops should both go from 0 to third_start.
You have a similar problem in the previous process with second_start, except it's doing it in the j loop.

Related

Implementation of multiple pipelines in C

First, I Saw already the all posts before. I took already a code from here https://stackoverflow.com/a/8439286/14888108
I have a problem I didn't know how to solve: when I do fork the pid is not 0 no matter what.
its a random number started like : 4013,4014 if I give [input: echo atb | grep "b"]
Here is my code:
EDITED AFFTER MISTAKE IN THE CODE SAME PROBLEM:
void Pipeline(char *input) {
int numPipes = 2 * countPipes(input);
int k = commends(input);
int j = 0;
for (int i = 0; i < k; i++) {
int pid = fork();
if (pid == 0) {
if (i != k-1) {
if (dup2(pipefds[j + 1], 1) < 0) {
perror("dup2");
exit(EXIT_FAILURE);
}
}
//if not first command&& j!= 2*numPipes
if (j != 2*numPipes && i != 0) {
if (dup2(pipefds[j - 2], 0) < 0) {
perror(" dup2");
exit(EXIT_FAILURE);
}
}
for (i = 0; i < 2 * numPipes; i++) {
close(pipefds[i]);
}
if (execvp(vec[i], vec) < 0) {
perror(vec[i]);
exit(EXIT_FAILURE);
}
} else if (pid < 0) {
prev++;
perror("error");
exit(EXIT_FAILURE);
}
j += 2;
}
for (int i = 0; i < 2 * numPipes; i++) {
close(pipefds[i]);
}
for (int i = 0; i < numPipes + 1; i++) {
wait(NULL);
}
printf("DONE!\n");
}
These lines:
int pid = fork();
prev = pid;
if (pid == prev+1) {
don't seem to make a lot of sense. If you copy pid into prev first, how can pid then ever be equal to prev + 1?
Also, you seem to be expecting a particular sequence of process id:s, that is not very likely or portable (or even nice). Other processes are busy creating and destroying processes in the background, I don't think you can assume that your particular process has a private pid space to fill.

Parallel c code using pthreads.h uses less than 100%CPU and is slower when using more threads

So I have a project where I needed to implement the game of life and then parallelise it in c. However, when I try using pthreads.h to parallelise it the program runs slower when introducing more threads and the %CPU is lower than 100% (when using top in the ubuntu terminal, I have an Ubuntu Windows subsystem). Here's my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <pthread.h>
/* Parallel code with PTHREADS v1 */
//Global variables
int N; // Size of the world
int nthreads; // Number of threads
pthread_mutex_t lock;
typedef struct info_thread
{
int threadID; // thread ID
int low; // lower limit of interval
int high; // higher limit of interval
int **world; // pointer to the world matrix
int **neighbors; // pointer to the neighbors matrix
//int **neighbors_2; // pointer to the neighbors_2 matrix
//int **one_step; // pointer to the one_step matrix
}t_info;
void * thread_func(void *arg);
void print_world(int **world);
void count_neighbors(int **world, int **neighbors);
void next_step(int **world, int **one_step, int **neighbors);
void update(int **world, int **one_step);
int compare(int **world, int **one_step, int **two_steps, int **old, int status);
int main(int argc, const char *argv[])
{
if (argc != 5)
{
printf("Give the following input arguments:\n");
printf("N: Size of the NxN world (integer)\n");
printf("Initial state: random (0), chessboard (1)\n");
printf("Output: Number of steps until final state (0) \n");
printf(" Number of steps until final state, initial and final states (1) \n");
printf(" Number of steps until final state and all states states (2) \n");
printf("Threads: Number of threads (integer)\n");
exit(0);
}
N = atoi(argv[1]);
const int pattern = atoi(argv[2]);
const int output = atoi(argv[3]);
nthreads = atoi(argv[4]);
// Create necessary matrices
const int n = N+1;
int **buffer = (int **)malloc(6 * n * sizeof(int *));
for(int i = 0; i < (6*n); i++)
{
buffer[i] = (int *)malloc(n*sizeof(int));
}
int **world = &buffer[0];
int **neighbors = &buffer[n];
int **neighbors_2 = &buffer[2*n];
int **one_step = &buffer[3*n];
int **two_steps = &buffer[4*n];
int **old = &buffer[5*n];
// Setting a random initial pattern
if(pattern == 0){
srand(time(0));
for (int i = 0; i < N; i++)
{
for (int j = 0; j < N; j++)
{
int r = rand() % 10;
if (r > 5)
world[i][j] = 1;
else
world[i][j] = 0;
}
}
}
// Setting a chessboard initial state
else if(pattern == 1){
for (int i = 0; i < N; i++)
{
for (int j = 0; j < N; j++)
{
if(i%2 == 0){
if(j%2 == 0)
world[i][j] = 0;
else
world[i][j] = 1;
}
else{
if(j%2 == 0)
world[i][j] = 1;
else
world[i][j] = 0;
}
}
}
}
if(output==1 || output==2){
printf("Initial state:\n");
print_world(world);
}
int status = 1;
int t = 1;
update(old, world);
// Create threads and input info
pthread_t thread[nthreads];
t_info threadinfo[nthreads];
const int interval = N/nthreads;
while(status == 1)
{
for (int k=0; k<nthreads; k++)
{
threadinfo[k].threadID = k;
threadinfo[k].low = k*interval;
threadinfo[k].high = (k+1)*interval-1;
threadinfo[k].world = world;
threadinfo[k].neighbors = neighbors;
}
threadinfo[nthreads-1].high = N;
// Predict one step forward
pthread_mutex_init(&lock, NULL);
for (int k=0; k<nthreads; k++)
pthread_create(&thread[k], NULL, thread_func, (void *)&threadinfo[k]);
for (int k=0; k<nthreads; k++)
pthread_join(thread[k],NULL);
pthread_mutex_destroy(&lock);
next_step(world, one_step, neighbors);
// Predict two steps forward
for (int k=0; k<nthreads; k++)
{
threadinfo[k].world = one_step;
threadinfo[k].neighbors = neighbors_2;
}
for (int k=0; k<nthreads; k++)
pthread_create(&thread[k], NULL, thread_func, (void *)&threadinfo[k]);
for (int k=0; k<nthreads; k++)
pthread_join(thread[k],NULL);
//count_neighbors(one_step,neighbors_2);
next_step(one_step, two_steps, neighbors_2);
// Compare all predicted steps
status = compare(world, one_step, two_steps, old, status);
// Update world with two steps
update(world, two_steps);
for(int i = 0; i < N; i++)
{
for(int j = 0; j < N; j+=2)
{
neighbors[i][j] = 0;
neighbors[i][j+1] = 0;
neighbors_2[i][j] = 0;
neighbors_2[i][j+1] = 0;
}
}
if((output == 2) && (status == 1)){
printf("Step %d:\n", t);
print_world(one_step);
printf("Step %d:\n", t+1);
print_world(two_steps);
}
// Save previous step
update(old, world);
//t+=1;
t+=2;
}
//printf("It took %d steps to reach the final state\n", t-2);
printf("It took %d steps to reach the final state\n", (t-3));
if(output==1 || output ==2){
printf("Final state:\n");
print_world(world);
}
for (int i = 0; i < (6*n); i++)
{
free(buffer[i]);
}
free(buffer);
}
void * thread_func(void *arg)
{
pthread_mutex_lock(&lock);
t_info *threadinfo = arg;
int threadID = threadinfo->threadID;
int low = threadinfo->low;
int high = threadinfo->high;
//int **world = threadinfo->world;
//int **neighbors = threadinfo->neighbors;
int i; //rows
int j; //col
for (i = low; i <= high; i++){
for (j = 0; j <= N-1; j++){
if (i > 0){
if (j > 0){
if (threadinfo->world[i-1][j-1] == 1)
threadinfo->neighbors[i][j] +=1;
}
if (j < N-1){
if (threadinfo->world[i-1][j+1] == 1)
threadinfo->neighbors[i][j] +=1;
}
if (threadinfo->world[i-1][j] == 1)
threadinfo->neighbors[i][j] +=1;
}
if (i < N-1){
if (j > 0){
if (threadinfo->world[i+1][j-1] == 1)
threadinfo->neighbors[i][j] +=1;
}
if (j < N-1){
if (threadinfo->world[i+1][j+1] == 1)
threadinfo->neighbors[i][j] +=1;
}
if (threadinfo->world[i+1][j] == 1)
threadinfo->neighbors[i][j] +=1;
}
if (j > 0){
if (threadinfo->world[i][j-1] == 1)
threadinfo->neighbors[i][j] +=1;
}
if(j < N-1){
if (threadinfo->world[i][j+1] == 1)
threadinfo->neighbors[i][j] +=1;
}
}
}
pthread_mutex_unlock(&lock);
pthread_exit(NULL);
}
void print_world(int **world)
{
for (int i = 0; i < N; i++)
{
for (int j = 0; j < N; j+=2)
{
printf("%d ", world[i][j]);
printf("%d ", world[i][j+1]);
}
printf("\n");
}
printf("\n");
}
void count_neighbors(int **world, int **neighbors)
{
int i; //rows
int j; //col
for (i = 0; i <= N-1; i++){
for (j = 0; j <= N-1; j++){
if (i > 0){
if (j > 0){
if (world[i-1][j-1] == 1)
neighbors[i][j] +=1;
}
if (j < N-1){
if (world[i-1][j+1] == 1)
neighbors[i][j] +=1;
}
if (world[i-1][j] == 1)
neighbors[i][j] +=1;
}
if (i < N-1){
if (j > 0){
if (world[i+1][j-1] == 1)
neighbors[i][j] +=1;
}
if (j < N-1){
if (world[i+1][j+1] == 1)
neighbors[i][j] +=1;
}
if (world[i+1][j] == 1)
neighbors[i][j] +=1;
}
if (j > 0){
if (world[i][j-1] == 1)
neighbors[i][j] +=1;
}
if(j < N-1){
if (world[i][j+1] == 1)
neighbors[i][j] +=1;
}
}
}
}
void next_step(int **world, int **one_step, int **neighbors)
{
int i, j;
for (i = 0; i < N; i++){
for (j = 0; j < N; j++){
if (world[i][j] == 1)
{
if (neighbors[i][j] == 2 || neighbors[i][j] == 3)
one_step[i][j] = 1;
else
one_step[i][j] = 0;
}
else if (world[i][j] == 0)
{
if (neighbors[i][j] == 3)
one_step[i][j] = 1;
else
one_step[i][j] = 0;
}
}
}
}
void update(int **world, int **one_step)
{
for (int i = 0; i < N; i++)
{
for (int j = 0; j < N; j+=2)
{
world[i][j] = one_step[i][j];
world[i][j+1] = one_step[i][j+1];
}
}
}
int compare(int **world, int **one_step, int **two_steps, int **old, int status)
{
int counter1=0, counter2=0, counter3=0;
for (int i = 0; i < N; i++)
{
for (int j = 0; j < N; j++)
{
if(world[i][j] == one_step[i][j])
counter1++;
if(world[i][j] == 0)
counter2++;
if(old[i][j] == two_steps[i][j])
counter3++;
}
}
if (counter1 == (N*N))
status = 0;
else if(counter2 == (N*N))
status = 0;
else if(counter3 == (N*N))
status = 0;
return status;
}
When I compile the code and run it using 2, 4 and 8 threads I get the following:
gcc -o gol gol.c -lpthread
time ./gol 500 1 0 2
It took 1670 steps to reach the final state
real 0m10.064s
user 0m8.971s
sys 0m0.246s
time ./gol 500 1 0 4
It took 1670 steps to reach the final state
real 0m15.694s
user 0m9.976s
sys 0m0.437s
time ./gol 500 1 0 8
It took 1670 steps to reach the final state
real 0m14.600s
user 0m10.400s
sys 0m0.855s
Also the %CPU using top is ~65% when using 2 threads, ~78% when using 4 threads and ~100% when using 8 threads. What am I doing wrong?
You've got 2 problems:
a) Creating threads and waiting for them to terminate adds overhead. Doing it inside a "while(status == 1)" loop means that you're paying for that extra overhead repeatedly. It'd be better to create the threads once (outside the loop) then re-use the existing threads, using something (e.g. condition variable) to make the threads wait for the next iteration of the loop.
b) Mutexes exist to prevent (unwanted) parallelism, and also have overhead. If the threads acquire a mutex, then do their work, then release a mutex; then you're deliberately preventing all parallelism between these threads. For your code, parallelism between the main thread and the newly created threads is also prevented (main thread sits waiting in a pthread_join()).
Essentially; you've added lots of overhead (creating and destroying threads, acquiring and releasing mutexes) and prevented all parallelism to ensure that there's no benefits to outweigh the extra overhead; leading to code that is worse than not using threads at all.
To fix this you need to find ways to ensure that threads can do useful work in parallel. The easiest way to do that would probably be to use 2 global arrays to represent the state of the world, where one of these arrays is "previous world state" and the other is "next world state", and where you swap (pointers to) the arrays between steps. In this case, during a step, "previous world state" is only being read (and many threads can read in parallel without a problem) and each thread can update different parts of "next world state" in parallel. Note that because the threads would write to each cell in "next world state" you won't need to clear "next world state" between steps either.
WARNING: To ensure that updating one element of the array won't cause "lack of atomicity" problems with other/adjacent elements in the array; you will need to either use an atomic type (sig_atomic_t, C11 I think) with a 2D array, or use "1D array of pointers to 1D arrays" (where each row can only be modified by one thread) and the element/s are volatile. Note that if the world state is an 8 * 8 grid you can probably represent a whole row with a single uint8_t (meaning that it could become "1D array of pointers to volatile uint8_t).
Basically (if you include the re-use of threads) it can be done without using any mutexes for anything other than worker threads waiting for the main thread to start the next step, and the main thread waiting for worker threads to complete the current step.
Also; instead of waiting for worker threads, the main thread can also participate in doing useful work. For example, if the world state is an 8 * 8 grid, then "main thread + 7 worker threads" can do a row each (in parallel) to ensure that all 8 rows are done. However, when threads have the same priority it's rarely sane to have more threads than CPUs; so it can be a good idea to check how many CPUs the computer has and limit the number of threads (e.g. if there are 4 CPUs, then you might have "main thread + 3 more threads do 2 rows each").

RoundRobin Using Linked List. Finish Time Calculation Issue

we are trying to achieve round robin algorithm using linked list.
But My logic has some errors.
When I try to run it for 3 process then the first process values are wrong and sometimes right for the other below processes.
Please Help me.
I tried Searching for logics
Code Link: https://pastebin.com/FkbtUEaQ
#include<stdio.h>
struct process
{
char na[20];
int at, bt, ft, tat, rem;
//float ntat;
} Q[5], temp;
void roundRobin()
{
int rr[20], q, x, k;
int f, r, n, i, j, tt = 0, qt, t, flag, wt = 0;
float awt = 0, antat = 0, atat = 0;
printf("Enter the no. of jobs:");
scanf("%d", &n);
for (r = 0; r < n; r++)// aceppting arrival; and burst time
{
printf("Enter process name,arrival time and burst time:\n");
scanf("%s%d%d", Q[r].na, &Q[r].at, &Q[r].bt);
}
printf("Enter quantum:\n");
scanf("%d", &qt);
for (i = 0; i < n; i++)
{
for (j = i + 1; j < n; j++)
{
if (Q[i].at < Q[j].at) {
temp = Q[i];
Q[i] = Q[j];
Q[j] = temp;
}
}
}
for (i = 0; i < n; i++)
{
Q[i].rem = Q[i].bt;
Q[i].ft = 0;
}
tt = 0;
q = 0;
rr[q] = 0;
do
{
for (j = 0; j < n; j++)
if (tt >= Q[j].at)
{
x = 0;
for (k = 0; k <= q; k++)
if (rr[k] == j)
x++;
if (x == 0)
{
q++;
rr[q] = j;
}
}
if (q == 0)
i = 0;
if (Q[i].rem == 0)
i++;
if (i > q)
i = (i - 1) % q;
if (i <= q)
{
if (Q[i].rem > 0)
{
if (Q[i].rem < qt)
{
tt += Q[i].rem;
Q[i].rem = 0;
} else
{
tt += qt;
Q[i].rem -= qt;
}
Q[i].ft = tt;
}
i++;
}
flag = 0;
for (j = 0; j < n; j++)
if (Q[j].rem > 0)
flag++;
} while (flag != 0);
printf("\n\n\t\tROUND ROBIN ALGORITHM");
printf("\n***************************");
printf("\nprocesses Arrival time burst time finish time tat wt ntat");
for (f = 0; f < n; f++) {
wt = Q[f].ft - Q[f].bt - Q[f].at;
Q[f].tat = Q[f].ft - Q[f].at;
Q[f].ntat = (float) Q[f].tat / Q[f].bt;
antat += Q[f].ntat;
atat += Q[f].tat;
awt += wt;
printf("\n\t%s\t%d\t%d\t%d\t%d\t%d %f", Q[f].na, Q[f].at, Q[f].bt,
Q[f].ft, Q[f].tat, wt, Q[f].ntat);
}
antat /= n;
atat /= n;
awt /= n;
printf("\nAverage tat is %f", atat);
printf("\nAverage normalised tat is %f", antat);
printf("\n average waiting time is %f", awt);
}
void main()
{
roundRobin();
getch();
clrscr();
}
The First Process Gives Wrong Values
processes | ArrivalTime | BurstTime | FinishTime | Tat | WaitTime
a 0 10 60 60 50
b 0 20 30 30 10
c 0 30 50 50 20
In the do while loop you use i to index the rr array with valid indexes 0 to q as well as the Q array with valid indexes 0 to n − 1, of which only the former is correct. So, you have to change every occurrence of Q[i] in this loop to Q[rr[i]].
After that, still the order of the statements
if (Q[rr[i]].rem == 0)
i++;
if (i > q)
i = (i - 1) % q;
is wrong - the test for Q[rr[i]].rem == 0 is to be done each time a new i is chosen, e. g.:
while (Q[rr[i %= q+1]].rem == 0) i++;

Parellel Programming: How can I apply 'MPI_Gather' or 'MPI_Scatter' instead of 'MPI_Isend' and 'MPI_Recv'

This is my code counting prime numbers, I want to use only collective communication among those processes. However, I got error when I changed my code using 'MPI_Scatter' and 'MPI_Gather' instead of MPI_Recv and MPI_Isend. What should I change for it?
This is my original code:
MPI_Request req;
MPI_Status status;
MPI_Init(&argc,&argv);
MPI_Comm_size(MPI_COMM_WORLD, &p);
MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
if( my_rank == 0){
printf("Input(50-1000) : ");
fflush(stdout);
scanf("%d",&w);
for(i=0; i<w; i++) data[i] = i+1;
}
MPI_Bcast(&w, 1, MPI_INT,0,MPI_COMM_WORLD);
MPI_Bcast(data, w, MPI_INT,0,MPI_COMM_WORLD);
if( my_rank != 0){
x = w/(p-1);
low = (my_rank-1)*x;
high = low+x-1;
for(num = data[low]; num <= data[high];num++){
result = 0;
t=1;
while(num>=t){
if(num%t==0)
result = result +1;
t += 1;
}
if(result==2) i += 1;
}
MPI_Isend(&i,1,MPI_INT,0,0,MPI_COMM_WORLD,&req);
}
if(my_rank == 0){
int j = 0;
for( j = 1; j < p; j++){
MPI_Recv(&i,1,MPI_DOUBLE,MPI_ANY_SOURCE,0,MPI_COMM_WORLD,&status);
printf("Process %d : There are %d prime numbers\n",status.MPI_SOURCE,i );
}
}
MPI_Finalize();
}
And the output is:
Input(50-1000) : 50
Process 1 : There are 5 prime numbers
Process 2 : There are 4 prime numbers
Process 3 : There are 2 prime numbers
Process 4 : There are 4 prime numbers
Here is the part where I changed my code:
if( my_rank != 0){
x = w/(p-1);
low = (my_rank-1)*x;
high = low+x-1;
for(num = data_send[low]; num <= data[high];num++){
result = 0;
t=1;
while(num>=t){
if(num%t==0)
result = result +1;
t += 1;
}
if(result==2) i += 1;
}
MPI_Scatter(data_send,1,MPI_INT,data_recv,1,MPI_INT,0,MPI_COMM_WORLD);
}
here is how you can use MPI_Gather()
int * results;
if( my_rank != 0){
x = w/(p-1);
low = (my_rank-1)*x;
high = low+x-1;
for(num = data[low]; num <= data[high];num++){
result = 0;
t=1;
while(num>=t){
if(num%t==0)
result = result +1;
t += 1;
}
if(result==2) i += 1;
}
} else {
results = (int *)malloc(p * sizeof(int));
}
MPI_Gather(&i, 1, MPI_INT, results, 1, MPI_INT, 0, MPI_COMM_WORLD);
if(my_rank == 0){
int j = 0;
for( j = 1; j < p; j++){
printf("Process %d : There are %d prime numbers\n",j, results[j]);
}
free(results);
}
note you can arrange this algo in order to also do computations on rank 0, and hence use p MPI tasks instead of p-1
MPI_Scatter is a collective operation and need to be called by all ranks. Same thing goes for MPI_Gather.
The means that: MPI_Scatter call should be moved outside of the if block in your code (similarly for MPI_Gather).
You can find an example here.

passing 2D Array to recursion

I am trying to make calculations with using fork in C.
I have a 2D array with members {1,2,3,4}, I have a function to get square for each member in the array. I will call this function with child processes.
For example for 3 child process output will be like this;
1.Child
1 4
9 16
----------
2.Child
1 16
81 256
----------
3.Child
1 256
6561 65536
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
int matrix[2][2] = {1, 2, 3 ,4 } ;
int main(){
forkFork(3);
}
void forkFork(int counter)
{
pid_t pid;
if(counter == 0)
{
exit(0);
}
if(counter > 0)
{
if ((pid = fork()) < 0)
{
perror("fork error :(");
}
else if (pid == 0)
{
matrixPower(matrix);
print(matrix);
}
else if(pid > 0)
{
forkFork(counter - 1);
}
}
}
void matrixPower(int m[2][2])
{
int i,j,k;
int result = 0;
for (i = 0; i < 2; i++)
{
for (j = 0; j < 2; j++)
{
result = matrix[i][j]*matrix[i][j];
m[i][j] = result;
result = 0;
}
}
}
void print(int a[2][2])
{
int row, col ;
for( row = 0; row < 2; row++ )
{
for( col = 0; col < 2 ; col++ )
{
printf("%d\t", a[row][col]);
}
puts("");
}
printf("-------------------------------\n");
}
I could not find a way to pass new array to recursion function...
The problem with your solution is that all forked processes are created by the main/parent process. Therefore, each forked process just inherits the address space of the parent whose matrix values are always {1, 2, 3, 4}. The solution is for each modifying process to create its child process. Thus a new child process inherits the modified matrix.
See my solution below for forkFork function which works as expected.
void forkFork(int counter)
{
pid_t pid;
if(counter == 0)
{
exit(0);
}
if(counter > 0)
{
if ((pid = fork()) < 0)
{
perror("fork error :(");
}
else if (pid == 0)
{
matrixPower(matrix);
print(matrix);
forkFork(counter - 1);
}
}
}

Resources