
Лаб. 4 ОСиС
.docxЛабораторная работа 4
#include <ctype.h>
#include <limits.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <getopt.h>
#include "find_min_max_2.h"
#include "utils_2.h"
pid_t *child_pids;
int pnum = -1;
void alarmFunc(int a){
for (int i = 0; i < pnum; i++) {
kill(child_pids[i], SIGKILL);
}
}
int main(int argc, char **argv) {
int seed = -1;
int array_size = -1;
bool with_files = false;
int timeout = -1;
signal(SIGALRM, alarmFunc);
while (true) {
int current_optind = optind ? optind : 1;
static struct option options[] = {{"seed", required_argument, 0, 0},
{"array_size", required_argument, 0, 0},
{"pnum", required_argument, 0, 0},
{"timeout", required_argument, 0, 0},
{0, 0, 0, 0}};
int option_index = 0;
int c = getopt_long(argc, argv, "f", options, &option_index);
if (c == -1) break;
switch (c) {
case 0:
switch (option_index) {
case 0:
seed = atoi(optarg);
if (seed <= 0) {
printf("seed is a positive number\n");
return 1;
}
break;
case 1:
array_size = atoi(optarg);
if (array_size <= 0) {
printf("array_size is a positive number\n");
return 1;
}
break;
case 2:
pnum = atoi(optarg);
if (pnum <= 0) {
printf("pnum is a positive number\n");
return 1;
}
break;
case 3:
timeout = atoi(optarg);
if (timeout < 0) {
printf("timeout must be a non-negative number\n");
return 1;
}
break;
default:
printf("Index %d is out of options\n", option_index);
}
break;
case '?':
break;
default:
printf("getopt returned character code 0%o?\n", c);
}
}
if (optind < argc) {
printf("Has at least one no option argument\n");
return 1;
}
if (seed == -1 || array_size == -1 || pnum == -1) {
printf("Usage: %s --seed \"num\" --array_size \"num\" --pnum \"num\" --timeout \"num\"\n",
argv[0]);
return 1;
}
int *array = malloc(sizeof(int) * array_size);
GenerateArray(array, array_size, seed);
int active_child_processes = 0;
struct timeval start_time;
gettimeofday(&start_time, NULL);
int fd[2];
if (!with_files) {
pipe(fd);
}
child_pids = malloc(sizeof(pid_t) * pnum);
for (int i = 0; i < pnum; i++) {
pid_t child_pid = fork();
if (child_pid >= 0) {
active_child_processes += 1;
child_pids[i] = child_pid;
if (child_pid == 0) {
struct MinMax min_max;
int begin = i * (array_size / pnum);
int end = (i + 1) * (array_size / pnum);
if (i == pnum - 1) {
end = array_size;
}
min_max = GetMinMax(array, begin, end);
if (with_files) {
char filename[20];
sprintf(filename, "result_%d.txt", i);
FILE *file = fopen(filename, "w");
fprintf(file, "%d %d\n", min_max.min, min_max.max);
fclose(file);
} else {
write(fd[1], &min_max.min, sizeof(min_max.min));
write(fd[1], &min_max.max, sizeof(min_max.max));
}
return 0;
}
} else {
printf("Fork failed!\n");
return 1;
}
}
if (timeout > 0) {
// sleep(timeout);
// for (int i = 0; i < pnum; i++) {
// kill(child_pids[i], SIGKILL); // Отправка SIGKILL всем дочерним процессам
alarm(timeout);
sleep(timeout);
}
while (active_child_processes > 0) {
wait(NULL);
active_child_processes -= 1;
}
struct MinMax min_max;
min_max.min = INT_MAX;
min_max.max = INT_MIN;
for (int i = 0; i < pnum; i++) {
int min = INT_MAX;
int max = INT_MIN;
if (with_files) {
char filename[20];
sprintf(filename, "result_%d.txt", i);
FILE *file = fopen(filename, "r");
fscanf(file, "%d %d", &min, &max);
fclose(file);
} else {
read(fd[0], &min, sizeof(min));
read(fd[0], &max, sizeof(max));
}
if (min < min_max.min) min_max.min = min;
if (max > min_max.max) min_max.max = max;
}
if (!with_files) {
close(fd[0]);
close(fd[1]);
}
struct timeval finish_time;
gettimeofday(&finish_time, NULL);
double elapsed_time = (finish_time.tv_sec - start_time.tv_sec) * 1000.0;
elapsed_time += (finish_time.tv_usec - start_time.tv_usec) / 1000.0;
free(array);
printf("Min: %d\n", min_max.min);
printf("Max: %d\n", min_max.max);
printf("Elapsed time: %fms\n", elapsed_time);
fflush(NULL);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main() {
pid_t pid;
// Создание дочернего процесса
if ((pid = fork()) == 0) {
// Дочерний процесс
printf("Дочерний процесс (PID: %d) завершился.\n", getpid());
exit(0); // Завершение дочернего процесса
} else if (pid > 0) {
// Родительский процесс
printf("Родительский процесс (PID: %d) спит 10 секунд...\n", getpid());
sleep(5); // Ожидание, чтобы дочерний процесс стал зомби
printf("Родительский процесс завершился.\n");
} else {
// Ошибка при создании процесса
printf("Ошибка fork");
return 1;
}
return 0;
}
Как появляются зомби-процессы: Дочерний процесс завершает свою работу с помощью exit(0). Он становится зомби, так как родительский процесс не вызвал wait().
Чем опасны: Каждый зомби-процесс занимает запись в таблице процессов. Если зомби-процессов становится слишком много, это может привести к исчерпанию ресурсов и невозможности создания новых процессов.
Как избавиться: Родительский процесс должен вызывать wait() или waitpid(), чтобы получить статус завершения дочернего процесса. Это удалит запись о процессе из таблицы процессов.
В process_memory.c выводятся адреса различных переменных и функции в памяти процесса.
etext: Указывает на адрес, где заканчивается сегмент текста (код программы). Это область памяти, где хранится исполняемый код.
edata: Указывает на адрес, где заканчивается сегмент инициализированных данных. Это область памяти, где хранятся глобальные и статические переменные, которые были инициализированы.
end: Указывает на адрес, где заканчивается сегмент неинициализированных данных (bss). Это область памяти, где хранятся глобальные и статические переменные, которые не были инициализированы.
CC=gcc
CFLAGS=-I.
new : parallel_min_max_2 zombie process_memory
parallel_min_max_2 : parallel_min_max_2.c utils_2.o find_min_max_2.o utils_2.h find_min_max_2.h
$(CC) -o parallel_min_max_2 utils_2.o find_min_max_2.o parallel_min_max_2.c $(CFLAGS)
zombie : zombie.c
$(CC) -o zombie -c zombie.c $(CFLAGS)
process_memory : process_memory.c
$(CC) -o process_memory -c process_memory.c $(CFLAGS)
utils_2.o : utils_2.h
$(CC) -o utils_2.o -c utils_2.c $(CFLAGS)
find_min_max_2.o : utils_2.h find_min_max_2.h
$(CC) -o find_min_max_2.o -c find_min_max_2.c $(CFLAGS)
clean :
rm utils_2.o find_min_max_2.o parallel_min_max_2 zombie process_memory
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include "utils_2.h"
#include "sum.h"
#include <pthread.h>
#include <getopt.h>
void *ThreadSum(void *args) {
struct SumArgs *sum_args = (struct SumArgs *)args;
unsigned long long int *result = malloc(sizeof(unsigned long long int));
*result = Sum(sum_args);
return (void *)result;
}
int main(int argc, char **argv) {
uint32_t threads_num = -1;
uint32_t seed = -1;
uint32_t array_size = -1;
while (true) {
int current_optind = optind ? optind : 1;
static struct option options[] = {
{"threads_num", required_argument, 0, 0},
{"seed", required_argument, 0, 0},
{"array_size", required_argument, 0, 0},
{0, 0, 0, 0}
};
int option_index = 0;
int c = getopt_long(argc, argv, "", options, &option_index);
if (c == -1) break;
switch (c) {
case 0:
switch (option_index) {
case 0:
threads_num = atoi(optarg);
if (threads_num <= 0) {
printf("threads_num must be a positive number\n");
return 1;
}
break;
case 1:
seed = atoi(optarg);
if (seed <= 0) {
printf("seed must be a positive number\n");
return 1;
}
break;
case 2:
array_size = atoi(optarg);
if (array_size <= 0) {
printf("array_size must be a positive number\n");
return 1;
}
break;
default:
printf("Index %d is out of options\n", option_index);
}
break;
case '?':
break;
default:
printf("getopt returned character code 0%o?\n", c);
}
}
if (optind < argc) {
printf("Has at least one no option argument\n");
return 1;
}
if (seed == -1 || array_size == -1 || threads_num == -1) {
printf("Usage: %s --seed \"num\" --array_size \"num\" --pnum \"num\" --timeout \"num\"\n",
argv[0]);
return 1;
}
pthread_t threads[threads_num];
int *array = malloc(sizeof(int) * array_size);
GenerateArray(array, array_size, seed);
struct SumArgs args[threads_num];
int chunk_size = array_size / threads_num;
clock_t start_time = clock();
for (uint32_t i = 0; i < threads_num; i++) {
args[i].array = array;
args[i].begin = i * chunk_size;
args[i].end = (i + 1) * chunk_size;
if (i == threads_num - 1) {
args[i].end = array_size;
}
if (pthread_create(&threads[i], NULL, ThreadSum, (void *)&args[i])) {
printf("Error: pthread_create failed!\n");
return 1;
}
}
unsigned long long int total_sum = 0;
for (uint32_t i = 0; i < threads_num; i++) {
unsigned long long int *sum;
pthread_join(threads[i], (void **)&sum);
total_sum += *sum;
//free(sum);
}
clock_t end_time = clock();
double time_taken = (double)(end_time - start_time) / CLOCKS_PER_SEC;
free(array);
printf("Total: %llu\n", total_sum);
printf("Time taken to calculate sum: %.6f seconds\n", time_taken);
return 0;
}
CC = gcc
CFLAGS = -I.
new: parallel_min_max_2 zombie process_memory psum
parallel_min_max_2: parallel_min_max_2.c utils_2.o find_min_max_2.o utils_2.h find_min_max_2.h
$(CC) -o parallel_min_max_2 utils_2.o find_min_max_2.o parallel_min_max_2.c $(CFLAGS)
zombie: zombie.c
$(CC) -o zombie zombie.c $(CFLAGS)
process_memory: process_memory.c
$(CC) -o process_memory process_memory.c $(CFLAGS)
psum: parallel_sum.o sum.o utils_2.o sum.h utils_2.h
$(CC) -o psum parallel_sum.o sum.o utils_2.o -lpthread $(CFLAGS)
utils_2.o: utils_2.c utils_2.h
$(CC) -c utils_2.c $(CFLAGS)
find_min_max_2.o: find_min_max_2.c find_min_max_2.h utils_2.h
$(CC) -c find_min_max_2.c $(CFLAGS)
sum.o: sum.c sum.h
$(CC) -c sum.c $(CFLAGS)
parallel_sum.o: parallel_sum.c sum.h utils_2.h
$(CC) -c parallel_sum.c $(CFLAGS)
clean:
rm -f utils_2.o find_min_max_2.o parallel_min_max_2 zombie process_memory parallel_sum.o sum.o psum