Для выполнения на компьютере какой-либо программы необходимо, чтобы она имела доступ к ресурсам компьютера

Вид материалаДокументы
Подобный материал:
1   2   3   4   5   6   7   8   9   10   ...   16
Для досрочного завершения потока можно воспользоваться функцией pthread_cancel(3). Единственным аргументом этой функции является идентификатор потока.
16. Взаимоисключения – программный подход и аппаратная поддержка.
Одной из причин зависимости результатов выполнения программ от порядка чередования команд может быть разделение одних и тех же данных между одновременно исполняемыми процессами.
Данная ситуация может рассматриваться как проявление общей проблемы использования разделяемых ресурсов (общих данных, файлов, устройств и т.п.). Для организации разделения ресурсов между несколькими процессами необходимо иметь возможность:
-       определения доступности запрашиваемых ресурсов (ресурс свободен и может быть выделен для использования, ресурс уже занят одним из процессов программы и не может использоваться дополнительно каким-либо другим процессом);
-       выделения свободного ресурса одному из процессов, запросивших ресурс для использования;
-       приостановки (блокировки) процессов, выдавших запросы на ресурсы, занятые другими процессами.
При разработке алгоритмов взаимоисключения должны соблюдаться следующие требования: Взаимоисключения должны осуществляться в принудительном порядке Процесс, прервавший или завершающий работу вне критического раздела, не должен влиять на другие процессы Не должно возникать ситуации бесконечного ожидания входа в критическую секцию Когда в критическом разделе нет ни одного процесса, любой процесс, запросивший возможность входа в к/р должен его немедленно получить. Не должно делаться никаких предположений ни о количестве процессов, ни об их относительной скорости выполнения/Любой процесс должен находиться в к/р ограниченное время
Алгоритм Петерсона - программный алгоритм взаимного исключения потоков исполнения кода, который изначально был сформулирован для 2-х поточного случая, но может быть обобщён для произвольного количества потоков. Алгоритм условно называется программным, т.к. не основан на использовании специальных команд процессора для запрета прерываний, блокировки шины памяти и т.д., используются только общие переменные памяти и цикл для ожидания входа в критическую секцию исполняемого кода. Глобальная переменная flag указывает положение каждого процесса по отношению к взаимоисключению, а глобальная переменная turn разрешает конфликты одновременности. Алгоритм представлен в листинге:
boolean flag [2];
int turn;
void P0(){
while(true){
flag[0] - true;
turn = 1;
while(flag[l] && turn == 1) /* Ничего не делать */;
/* Критический раздел */; flagfO] = false;
/* Остальной код */;
}
}
void P1(){
while(true){
flag[l] = true;
turn = 0;
while(flag[0] && turn == 0}
/* Ничего не делать */;
/* Критический раздел */; flag[l] = false;
/* Остальной код */;
}
}
void main(){
flag[0] = false;
flag[l] = false;
parbegin(P0,P1);
}
Выполнение условий взаимоисключения легко показать. Рассмотрим процесс РО. После того как flag[0] установлен им равным true, PI войти в критический раздел не может. Если же Р1 уже находится в критическом разделе, то flag[l] = true и для РО вход в критический раздел заблокирован. Однако взаимная блокировка в данном алгоритме предотвращена. Предположим, что РО заблокирован в своем цикле while. Это означает, что flag[l] равен true, a turn = 1. РО может войти в критический раздел, когда либо flag[l] становится равным false, либо turn становится равным О. Рассмотрим три исчерпывающих случая.
Р1 не намерен входить в критический раздел. Такой случай невозможен, поскольку при этом выполнялось бы условие flag[l] = false.
P1 ожидает вход в критический раздел. Такой случай также невозможен, поскольку если turn = 1, то Р1 способен войти в критический раздел.
Р1 циклически использует критический раздел, монополизировав доступ к нему. Этого не может произойти, поскольку Р1 вынужден перед каждой попыткой входа в критический раздел дать такую возможность процессу РО, устанавливая значение turn равным 0.
Следовательно, у нас имеется простое решение проблемы взаимных исключений для двух процессов. Впрочем, алгоритм Петерсона легко обобщается на случай n процессов.
Алгоритм Деккера
int ProcessNum=1; // номер процесса для доступа
к ресурсу
int ResourceProc1 = 0; // = 1 – ресурс занят
процессом 1
int ResourceProc2 = 0; // = 1 – ресурс занят
процессом 2
Process_1() {
while (1) {
ResourceProc1 = 1; // процесс 1 пытается занять ресурс
/* цикл ожидания доступа к ресурсу */
while ( ResourceProc2 == 1 ) {
if ( ProcessNum == 2 ) {
ResourceProc1 = 0;
// повторять, пока ресурс занят процессом 2
while ( ProcessNum == 2 );
ResourceProc1 = 1;
}
}
< Использование общего ресурса >
ProcessNum  = 2;
ResourceProc1 = 0;
}
}
Process_2() {
while (1){
ResourceProc2 = 1; // процесс 2 пытается занять ресурс