Лаб. работа “Работа с процессами в 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?