Finished Topic 3 and 4

This commit is contained in:
Sergiusz Warga 2021-03-24 18:52:27 +01:00
parent e7e743923d
commit 5f6459ea75
9 changed files with 369 additions and 8 deletions

View File

@ -2,13 +2,12 @@
// Wrote for Computer Networks and Systems lab classes
// AUTHOR : Sergiusz Warga
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#define BUFFER_SIZE 8 // TODO: Think about it.

View File

@ -37,3 +37,17 @@ descendant 2 - from index 200000 to 299999
...
The parent process waits for the descendant processes to complete their calculations and then determines the average value of the array elements based on the obtained partial averages.
## Task 4
The main program allocates a 1000000-element array of floating point numbers on the heap.
Then it fills it with random values from the range -1....1
After preparing the array it creates 10 child processes. The task of each of the child processes is to determine the sum of the elements of the array fragment:
descendant 0 - from index 0 to 99999
descendant 1 - from index 100000 to 199999
descendant 2 - from index 200000 to 299999
...
After determining the sum the child processes write it to the file named "sum<PID>.txt" and finish their work.
The parent process waits for the completion of calculations by the child processes and then determines the average value of the array elements based on the contents of files with partial results.

View File

@ -49,8 +49,8 @@ int main() {
exit(EXIT_FAILURE);
}
if (pid == 0){ // If this is a child process.
int sum = child_task(array, (int)(i*SPAN));
exit(sum);
int avg = child_task(array, (int)(i*SPAN));
exit(avg);
}
children_pids[i] = pid;
}

91
Topic-3/task_3_4.c Normal file
View File

@ -0,0 +1,91 @@
//
// Written for Computer Networks and Systems lab classes
// AUTHOR : Sergiusz Warga
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <time.h>
#include <unistd.h>
#define N_OF_ELEMENTS 1e6
#define N_OF_CHILDREN 10
#define SPAN (int)(N_OF_ELEMENTS/N_OF_CHILDREN)
union floaty {
float number;
char bytes[sizeof(float)];
};
int child_task(float * array, int start) {
union floaty sum;
for (int i = start; i < start + SPAN; ++i ) {
sum.number += array[i];
}
char filename[16];
snprintf(filename, 16, "sum%d.txt", getpid());
int file = open(filename, O_CREAT | O_WRONLY);
write(file, sum.bytes, sizeof(sum));
close(file);
return 0;
}
float avg(float * array) {
float sum = 0;
for (int i = 0; i < N_OF_CHILDREN; ++i) {
sum += array[i];
}
return sum/N_OF_ELEMENTS;
}
int main() {
srandom(time(NULL));
int status[N_OF_CHILDREN];
float sums[N_OF_CHILDREN] = {0};
int children_pids[N_OF_CHILDREN];
float * array = malloc(N_OF_ELEMENTS * sizeof(float));
for (int i = 0; i < N_OF_ELEMENTS; ++i) {
array[i] = 2*(float)random()/RAND_MAX - 1; // Nasty
}
pid_t pid;
for (int i = 0; i < N_OF_CHILDREN; ++i) {
pid = fork();
if (pid == -1) { // If something went wrong.
perror("Fork: ");
exit(EXIT_FAILURE);
}
if (pid == 0){ // If this is a child process.
child_task(array, (int)(i*SPAN));
exit(EXIT_SUCCESS);
}
children_pids[i] = pid;
}
for (int i = 0; i < N_OF_CHILDREN; ++i) {
waitpid(children_pids[i], &status[i], 0);
}
char filename[16];
union floaty sum;
for (int i = 0; i < N_OF_CHILDREN; ++i) {
sum.number = 0;
snprintf(filename, 16, "sum%d.txt", children_pids[i]);
int file = open(filename, O_RDONLY);
read(file, sum.bytes, sizeof(sum));
sums[i] = sum.number;
close(file);
}
printf("avg = %f\n", avg(sums));
return 0;
}

54
Topic-4/README.md Normal file
View File

@ -0,0 +1,54 @@
# Topic 4 Pipes
# Task 1
Perform basic test with pipe in single process
1) create a pipe
2) write some data
3) read it back
4) verify
man 2 pipe
man 2 read
man 2 write
## Task 2
As you remember - fork() creates an almost identical copy of the parent process. Interestingly, this copy "inherits" parent's process open file descriptors
The child inherits copies of the parent's set of open file descriptors. Each file descriptor in the child refers to the same open file description (see open(2)) as the corresponding file descriptor in the parent. This means that the two file descriptors share open file status flags, file offset, and signal-driven I/O attributes (see the description of F_SETOWN and F_SETSIG in fcntl(2)).
This means that if you use pipe before fork, you get a pipeline that you can write to in one process and read in another
Please modify your program from Task 2.1 so that the parent writes to the pipe and the child reads and displays received data
## Task 3
Usually - for added security - you close unnecessary ends of the pipe after the fork. That is, if the pipeline is used to send data from the parent to the child, then the parent closes its 'reading' endpoint, and the child closes its writing side.
If we want two-way communication, we create two pipes (and close their ends accordingly)
Task:
Create a simple "echo server"
The child in an infinite loop:
receives data from the parent (line of text, you can assume it is not longer than 8000 characters)
converts all lowercase letters into uppercase (you can use the toupper function)
sends the result back to the parent
In the parent process, test sending several texts to the child, read and display the answers
## Task 4
Modify Task-3-4 to use pipes to pass return values from child processes to their parent.
You may want to create a separate pipe for each child (or deal with buffering issues...)

27
Topic-4/task_4_1.c Normal file
View File

@ -0,0 +1,27 @@
//
// Written for Computer Networks and Systems lab classes
// AUTHOR : Sergiusz Warga
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
int main() {
int pipefd[2];
if (pipe(pipefd) < 0){
fprintf(stderr,"Something went wrong!\n");
return -1;
}
int in = 42;
int out = 0;
write(pipefd[1], &in, sizeof(in));
read(pipefd[0], &out, sizeof(out));
close(pipefd[0]);
if (!(in-out)) printf("Pipe works just fine!\n");
return 0;
}

43
Topic-4/task_4_2.c Normal file
View File

@ -0,0 +1,43 @@
//
// Written for Computer Networks and Systems lab classes
// AUTHOR : Sergiusz Warga
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
int main() {
int pipefd[2];
if (pipe(pipefd) < 0){
fprintf(stderr,"Something went wrong!\n");
return -1;
}
int in = 42;
int out = 0;
int status;
pid_t pid;
pid = fork();
if (pid == -1) { // If something went wrong.
perror("Fork: ");
exit(EXIT_FAILURE);
}
if (pid == 0) { // If this is a child process.
read(pipefd[0], &out, sizeof(out));
printf("%d\n", out);
close(pipefd[0]);
exit(EXIT_SUCCESS);
}
write(pipefd[1], &in, sizeof(in));
wait(&status);
close(pipefd[1]);
return 0;
}

54
Topic-4/task_4_3.c Normal file
View File

@ -0,0 +1,54 @@
//
// Written for Computer Networks and Systems lab classes
// AUTHOR : Sergiusz Warga
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
void echo(int parent_to_child, int child_to_parent) {
while(1) {
char buff[8000] = {0};
int read_bytes = read(parent_to_child, &buff, sizeof(buff));
write(child_to_parent, &buff, read_bytes);
}
}
int main() {
int parent_to_child[2], child_to_parent[2];
if (pipe(parent_to_child) < 0 || pipe(child_to_parent) < 0 ){
fprintf(stderr,"Something went wrong!\n");
return -1;
}
int status;
pid_t pid;
pid = fork();
if (pid == -1) { // If something went wrong.
perror("Fork: ");
exit(EXIT_FAILURE);
}
if (pid == 0) { // If this is a child process.
echo(parent_to_child[0], child_to_parent[1]);
exit(EXIT_SUCCESS);
}
char buff[8000];
char messages[3][32] = {"Hello there!", "Second message.", "Bye!"};
for (int i = 0; i < 3; ++i) {
write(parent_to_child[1], &messages[i], sizeof(messages[i]));
read(child_to_parent[0], buff, sizeof(buff));
printf("%s\n", buff);
}
wait(&status);
close(parent_to_child[1]);
close(child_to_parent[0]);
return 0;
}

79
Topic-4/task_4_4.c Normal file
View File

@ -0,0 +1,79 @@
//
// Written for Computer Networks and Systems lab classes
// AUTHOR : Sergiusz Warga
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <time.h>
#include <unistd.h>
#define N_OF_ELEMENTS 1e6
#define N_OF_CHILDREN 10
#define SPAN (int)(N_OF_ELEMENTS/N_OF_CHILDREN)
int child_task(double * array, int start, int pipe) {
double sum;
for (int i = start; i < start + SPAN; ++i ) {
sum += array[i];
}
write(pipe, &sum, sizeof(sum));
close(pipe);
return 0;
}
double avg(double * array) {
double sum = 0;
for (int i = 0; i < N_OF_CHILDREN; ++i) {
sum += array[i];
}
return sum/N_OF_ELEMENTS;
}
int main() {
int children_pids[N_OF_CHILDREN];
pid_t pid;
double sums[N_OF_CHILDREN] = {0};
double * array = malloc(N_OF_ELEMENTS * sizeof(double));
srandom(time(NULL));
for (int i = 0; i < N_OF_ELEMENTS; ++i) {
array[i] = 2*(double)random()/RAND_MAX - 1; // Nasty
}
int child_to_parent[N_OF_CHILDREN][2];
for (int i = 0; i < N_OF_CHILDREN; ++i) {
if (pipe(child_to_parent[i]) < 0 ){
fprintf(stderr,"Something went wrong!\n");
return -1;
}
pid = fork();
if (pid == -1) { // If something went wrong.
perror("Fork: ");
exit(EXIT_FAILURE);
}
if (pid == 0){ // If this is a child process.
child_task(array, (int)(i*SPAN), child_to_parent[i][1]);
exit(EXIT_SUCCESS);
}
children_pids[i] = pid;
}
for (int i = 0; i < N_OF_CHILDREN; ++i) {
read(child_to_parent[i][0], &sums[i], sizeof(double));
close(child_to_parent[i][0]);
}
printf("avg = %f\n", avg(sums));
return 0;
}