Задания:
Часть 1. Процессы
1.1. Изучите команды ps и kill. Запустите любую свою программу, используя в конце &
(например: ./a.out & ). Дайте письменно объяснение результата работы команды ps.
Опишите также, как завершить процесс a.out ?
1.3. Изучите функции семейства exec, а именно execv(), execl(), execvp()и execlp(). Объясните
письменно разницу между этими функциями.
Часть 2. Потоки
Лист
Лабораторная работа №2 ТОГУ, ИС-51, Храмцов А.А.
по Системному ПО 1
2.2 Напишите программу на языке C/C++, в которой:
1) Запускается четное количество потоков параллельно.
2) Каждый нечетный поток (например, первый) создает файл с именем из своего PID,
записывает в него произвольное число символов (от нескольких символов до сотен
миллионов символов) и закрывает этот файл.
3) Каждый четный поток (например, второй) открывает файл, созданный предыдущим
потоком с нечетным номером (в нашем случае первым), читает его, считает
количество символов в файле и закрывает его; при этом четный поток не должен
иметь никакой информации о количестве записываемых в файл символов и о том,
закончена ли запись в файл нечетным потоком.
4) Каждый из потоков выводит следующую информацию: ThreadID, PID, PPID, время,
имя файла, количество записанных или считанных символов.
5) Количество пар создаваемых потоков передается аргументом в программу с
командной строки. Программа должна ждать завершения работы всех потоков,
анализировать и сообщать о причинах завершения потоков. Для передачи имен
файлом между потоками можно использовать символьный массив в основной
программе.
Ход работы:
Часть 1
Задание 1
Команда ps выводит все процессы для текущей оболочки bash. Так же с помощью
команды ps –a можно вывести все процессы системы.
Задание 2
Команда jobs выводит список процессов, выполняемых в фоновом режиме.
Лист
Лабораторная работа №2 ТОГУ, ИС-51, Храмцов А.А.
по Системному ПО 2
1 строка - общая информация (top)
Первая строка выводит данные по порядку:
текущее время (06:40:39)
время работы системы (up 1 min)
количество открытых пользовательских сессий (1 user)
среднюю загрузку системы (load average: 3.39, 1.60, 0.60), три значения соответствуют
загрузке в последнюю минуту, пять минут и пятнадцать минут соответственно.
Лист
Лабораторная работа №2 ТОГУ, ИС-51, Храмцов А.А.
по Системному ПО 3
3 строка - статистика использования центрального процессора (cpu)
Лист
Лабораторная работа №2 ТОГУ, ИС-51, Храмцов А.А.
по Системному ПО 4
Для переключения процесса в фоновый режим нужно:
При запуске программы поставить в конце знак амперсанта (program &)
Или
1) Остановить процесс сочетанием Ctrl-Z
2) С помощью команды bg перевести его в фоновый режим
Задание 3
Функция exec() загружает и запускает другую программу. Таким образом, новая
программа полностью замещает текущий процесс. Новая программа начинает свое выполнение с
функции main.
Задание 4
Листинг
Base_Program
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <iostream>
#include <string.h>
#include <time.h>
#include <sys/wait.h>
#include <map>
#include <sys/errno.h>
Лист
Лабораторная работа №2 ТОГУ, ИС-51, Храмцов А.А.
по Системному ПО 5
using namespace std;
int main(int argc, char *argv[])
{
map<int, int> pID_To_Number;
int BaseProgram_pID = getpid();
time_t Time = time(0);
cout << '\n' << "Base Program With pID = " << BaseProgram_pID << " And ppID = " << getppid() <<
" Launched at " << ctime(&Time) << '\n';
////////
if (argv[1][0] != 'd' || argv[1][1] != 0)
{
ChildProgramPath = argv[1];
}
for (int cntr = 2; cntr <= argc - 1; cntr++)
{
int cpID = 0;
////////
if ((cpID = fork()) > -1)
{
int LaunchingProcessNumber = atoi(argv[cntr]);
char *ArgumentsForNewProcess[2];
////////////
if (getpid() != BaseProgram_pID)
{
cout << '\n' << "Process number " << LaunchingProcessNumber << " with ID " << getpid() <<
" and parent ID "
<< getppid() << " started execution at " << ctime(&Time);
ArgumentsForNewProcess[0] = argv[cntr];
switch (LaunchingProcessNumber)
{
case 1:
{
if (execv(ChildProgramPath, ArgumentsForNewProcess) != 0)
{
return errno;
}
}
break;
case 2:
Лист
Лабораторная работа №2 ТОГУ, ИС-51, Храмцов А.А.
по Системному ПО 6
{
if (execl(ChildProgramPath, argv[cntr], NULL)!= 0)
{
return errno;
}
}
break;
case 3:
{
if (execvp(ChildProgramPath, ArgumentsForNewProcess)!= 0)
{
return errno;
}
}
break;
case 4:
{
if (execlp(ChildProgramPath, argv[cntr], NULL)!= 0)
{
return errno;
}
}
break;
}
}
else
{
pID_To_Number.insert(pair<int, int>(cpID, LaunchingProcessNumber));
}
}
else
{
cout << "Could not fork a new process " << '\n';
}
}
int Status;
int JustFinished_pID;
int JustFinished_ProcessNumber;
//Waiting For ALL Child Processes To Finish
Лист
Лабораторная работа №2 ТОГУ, ИС-51, Храмцов А.А.
по Системному ПО 7
while ((JustFinished_pID = waitpid(-1, &Status, 0)) != -1)
{
auto it = pID_To_Number.find(JustFinished_pID);
if (it != pID_To_Number.end())
{
JustFinished_ProcessNumber = it->second;
}
cout << "Process number " << JustFinished_ProcessNumber << " finished at " << ctime(&Time) <<
" with " <<
((Status != 0) ? strerror(WEXITSTATUS(Status)) : " no errors.") << '\n';
Status = 0;
errno = 0;
}
cout << '\n' << "Base Program With pID = " << BaseProgram_pID << " And ppID = " << getppid() <<
" Stopped at " << ctime(&Time) << '\n';
}
Child_Process
#include <stdlib.h>
#include <unistd.h>
Лист
Лабораторная работа №2 ТОГУ, ИС-51, Храмцов А.А.
по Системному ПО 8
Результат работы:
Часть 2
Задание 1
1) Программа создает NKIDS параллельных процессов, каждому из которых передается
число на 1 большее предыдущего. Далее каждый процесс прибавляет свое полученное число к
сумме, состоящей из чисел, полученных выполненными потоками. В результате печатается сумма
этих чисел.
2) При запуске программы несколько раз с сохранением числа NKIDS результат зависит от
того в какой последовательности будут выполнены потоки.
При изменении числа NKIDS будет создано разное количество потоков и им будут
переданы разные числа. В результате сумма изменится.
Задание 2
Листинг
Threads
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
Лист
Лабораторная работа №2 ТОГУ, ИС-51, Храмцов А.А.
по Системному ПО 9
#include <iostream>
#include <fstream>
#include <string.h>
#include <cstdlib>
#include <math.h>
#include <sys/errno.h>
struct ThreadData
{
int ThreadNumber;
ThreadData* PreviousThread;
pthread_t ThreadID;
string FileToOperateOn;
bool WorkFinished = false;
};
Лист
Лабораторная работа №2 ТОГУ, ИС-51, Храмцов А.А.
по Системному ПО 10
OutputFile.flush();
OutputFile.close();
RecievedThreadData->WorkFinished = true;
cout << "Thread Number " << RecievedThreadData->ThreadNumber << ", With ThreadID
= " << pthread_self() << ", pID = " << getpid() <<
", ppID = " << getppid() << ", Finished Writing " << SymbolToWriteCount << " Symbols
To File " << RecievedThreadData->FileToOperateOn <<
" at " << ctime(&Time) << endl;
}
else
{
cout << "Thread number " << RecievedThreadData->ThreadNumber << ": Failed to open
file " << RecievedThreadData->FileToOperateOn << endl;
}
}
Лист
Лабораторная работа №2 ТОГУ, ИС-51, Храмцов А.А.
по Системному ПО 11
RecievedThreadData->WorkFinished = true;
cout << "Thread Number " << RecievedThreadData->ThreadNumber << ", With ThreadID = "
<< pthread_self() << ", pID = " << getpid() << ", ppID = " << getppid()
<< ", Finished Reading File " << RecievedThreadData->FileToOperateOn << " at " <<
ctime(&Time) << ". It Contained "
<< TotalSymbols << " Symbols." << endl;
}
Лист
Лабораторная работа №2 ТОГУ, ИС-51, Храмцов А.А.
по Системному ПО 12
int ThreadPairCount = atoi(argv[1]);
PrintFileToTerminal = atoi(argv[2]);
DeleteFilesOnExit = atoi(argv[3]);
pthread_t *ThreadIDs = new pthread_t[ThreadPairCount * 2];
ThreadData *DataForThreads = new ThreadData[ThreadPairCount * 2];
for (int cntr = 0; cntr < ThreadPairCount * 2; cntr++)
{
//Setting Thread Number (For Thread To Decide: Write To File Or Read It?)
DataForThreads[cntr].ThreadNumber = cntr + 1;
if (cntr > 0)
{
DataForThreads[cntr].PreviousThread = &DataForThreads[cntr - 1];
}
//Creating Threads
int ThreadCreationStatus = pthread_create(&ThreadIDs[cntr], NULL,
Thread_StartingPoint, &DataForThreads[cntr]);
if (ThreadCreationStatus != 0)
{
cout << "Failed To Create Thread Number " << cntr + 1 << " : " << strerror(errno);
errno = 0;
ThreadCreationStatus = 0;
}
}
for (int cntr = 0; cntr < ThreadPairCount * 2; cntr++)
{
int ThreadEndStatus = pthread_join(ThreadIDs[cntr], NULL);
if (ThreadEndStatus != 0)
{
cout << "Thread Number " << DataForThreads[cntr].ThreadNumber << " Exited With
Failure: " << strerror(errno) << endl;
}
}
if (DeleteFilesOnExit)
{
for (int cntr = 0; cntr < ThreadPairCount * 2; cntr++)
Лист
Лабораторная работа №2 ТОГУ, ИС-51, Храмцов А.А.
по Системному ПО 13
{
remove(DataForThreads[cntr * 2].FileToOperateOn.c_str());
}
}
}
Результат выполнения
Лист
Лабораторная работа №2 ТОГУ, ИС-51, Храмцов А.А.
по Системному ПО 14
Задание 3
Атрибуты являются способом определить поведение потока, отличное от поведения по
умолчанию. При создании потока с помощью pthread_create() или при инициализации
переменной синхронизации может быть определен собственный объект атрибутов. Атрибуты
определяются только во время создания потока; они не могут быть изменены в процессе
использования.
Лист
Лабораторная работа №2 ТОГУ, ИС-51, Храмцов А.А.
по Системному ПО 15