Лаб. работа “Работа с процессами в Linux”
Цель лабораторной работы
Изучение основных аспектов работы с процессами в операционной системе Linux с целью приобретения практических навыков управления процессами, мониторинга и анализа их работы.
Задачи лабораторной работы
- Изучение основных понятий в системном программировании относительно процессов в Linux (процессы, идентификаторы процессов, дерево процессов и т. д.).
- Ознакомиться с командами и утилитами Linux для работы с процессами (ps, top, kill и т. д.) и их ключами.
- Создать простые процессоы с использованием системных вызовов fork() и exec().
- Изучить механизмы коммуникации между процессами (каналы, сокеты, очереди сообщений).
- Оформить отчет о выполненной работе, включающий описание поставленных задач, исходный код программ и результаты тестирования.
Порядок выполнения работы
Создайте программу на языке Си, которая использует системные вызовы
fork()для создания нового процесса.Используйте системные вызовы
exec()в дочернем процессе для выполнения другой программы (например,ls,ps, или ваша собственная программа).Изучите механизм каналов (
pipes) и реализуйте коммуникацию между родительским и дочерним процессами через канал.Изучите семафоры (
semaphores) и реализуйте пример синхронизации между несколькими процессами.
Примеры
Пример 1: Создание нового процесса с помощью системного вызова fork():
#include <stdio.h>
#include <unistd.h>
int main() {
pid_t pid;
pid = fork();
if (pid < 0) {
fprintf(stderr, "Ошибка при вызове fork()\n");
return 1;
} else if (pid == 0) {
printf("Это дочерний процесс (PID: %d)\n", getpid());
} else {
printf("Это родительский процесс (PID: %d), дочерний процесс создан (PID: %d)\n", getpid(), pid);
}
return 0;
}Пример 2: Использование системного вызова exec() для выполнения программы в созданном процессе:
#include <stdio.h>
#include <unistd.h>
int main() {
pid_t pid;
pid = fork();
if (pid < 0) {
fprintf(stderr, "Ошибка при вызове fork()\n");
return 1;
} else if (pid == 0) {
printf("Это дочерний процесс (PID: %d)\n", getpid());
execl("/bin/ls", "ls", "-l", NULL);
} else {
printf("Это родительский процесс (PID: %d), дочерний процесс создан (PID: %d)\n", getpid(), pid);
}
return 0;
}Пример 3: Использование каналов (pipes) для обмена данными между процессами:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main() {
int pipefd[2];
pid_t pid;
char buffer[20];
if (pipe(pipefd) == -1) {
perror("pipe");
exit(EXIT_FAILURE);
}
pid = fork();
if (pid == -1) {
perror("fork");
exit(EXIT_FAILURE);
}
if (pid == 0) {
close(pipefd[0]); // Закрываем конец для чтения в дочернем процессе
write(pipefd[1], "Привет от дочернего процесса", 30);
close(pipefd[1]); // Закрываем конец для записи в дочернем процессе
exit(EXIT_SUCCESS);
} else {
close(pipefd[1]); // Закрываем конец для записи в родительском процессе
read(pipefd[0], buffer, sizeof(buffer));
printf("Родительский процесс прочитал: %s\n", buffer);
close(pipefd[0]); // Закрываем конец для чтения в родительском процессе
}
return 0;
}Пример 4: Использование семафоров (semaphores) для синхронизации между процессами:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#define SEM_KEY 1234
union semun {
int val;
struct semid_ds *buf;
unsigned short *array;
};
int main() {
int sem_id;
struct sembuf sops;
// Создание семафора
sem_id = semget(SEM_KEY, 1, IPC_CREAT | 0666);
if (sem_id == -1) {
perror("semget");
exit(EXIT_FAILURE);
}
// Установка начального значения семафора
union semun arg;
arg.val = 1;
if (semctl(sem_id, 0, SETVAL, arg) == -1) {
perror("semctl");
exit(EXIT_FAILURE);
}
pid_t pid = fork();
if (pid == -1) {
perror("fork");
exit(EXIT_FAILURE);
}
if (pid == 0) {
sops.sem_num = 0;
sops.sem_op = -1; // Уменьшаем семафор
sops.sem_flg = 0;
semop(sem_id, &sops, 1); // Захватываем семафор
printf("Дочерний процесс захватил семафор\n");
sops.sem_op = 1; // Увеличиваем семафор
semop(sem_id, &sops, 1); // Освобождаем семафор
} else {
sops.sem_num = 0;
sops.sem_op = -1; // Уменьшаем семафор
sops.sem_flg = 0;
semop(sem_id, &sops, 1); // Захватываем семафор
printf("Родительский процесс захватил семафор\n");
sops.sem_op = 1; // Увеличиваем семафор
semop(sem_id, &sops, 1); // Освобождаем семафор
}
return 0;
}Контрольные вопросы
- Что такое процесс в операционной системе Linux?
- Каковы основные характеристики процесса (идентификатор процесса, родительский процесс, состояние процесса)?
- Как создать новый процесс с использованием системного вызова fork()?
- Как процесс может выполнить другую программу с помощью системного вызова exec()?
- Какие команды и утилиты Linux используются для работы с процессами (например, ps, top, kill) и какие ключи часто используются с ними?
- Какие механизмы коммуникации между процессами существуют в Linux?
- Какие действия могут быть выполнены над процессом с помощью команды kill?
- Какие утилиты мониторинга можно использовать для анализа работы процессов в реальном времени?
- Как можно определить, сколько ресурсов (памяти, CPU и т. д.) потребляет определенный процесс?
- Какие меры безопасности могут быть применены при работе с процессами в Linux?