The OpenNET Project / Index page

[ новости /+++ | форум | wiki | теги | ]

Каталог документации / Раздел "Программирование, языки" / Оглавление документа
next up previous contents
Next: Очереди сообщений. Up: Блокировка файлов. Previous: Режимы блокировки.   Contents

Блокировка частей файла и тупики.

Взаимная блокировка процессов может возникнуть из-за блокировки файлов. Пусть, например, процесс номер 1 пытается установить блокировку в некотором файле dead.txt в позиции 10.

Другой процесс с номером 2 организует блокировку того же самого файла в позиции 20. Эта ситуация еще управляема. Далее процесс 1 хочет организовать следующую блокировку в позиции 20, где уже стоит блокировка процесса 2. При этом используется команда F_SETLKW. При этом процесс 1 приостанавливается до тех пор, пока процесс 2 снова не освободит со своей стороны блокировку в позиции 20. Теперь процесс 2 пытается организовать в позиции 10, где процесс 1 уже поставил блокировку, такую же блокировку командой F_SETLKW, и также приостанавливается и ждет, пока процесс 1 снимет блокировку. Теперь оба процесса, номер 1 и номер 2, приостановлены и оба ждут друг друга (F_SETLKW), образуя дедлок. Никакой из процессов не возобновит свое выполнение.

Причины, по которым эта ситуация возникает, во многом вызваны неудачным проектированием алгоритмов. В UNIX не предусмотрены механизмы определения и предотвращения тупика. Наличие этих механизмов существенно влияет на производительность системы, поэтому ответственность за предотвращение тупика ложится на программиста.

Пример программы, вызывающей тупик, приведен ниже (рис. 16):

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <unistd.h>

#include <stdio.h>

#include <errno.h>

extern int errno;

 

void status(struct flock *lock)

{

  printf("Status: ");

  switch(lock->l_type)

  {

    case F_UNLCK: printf("F_UNLCK\n"); break;

    case F_RDLCK: printf("F_RDLCK (pid: %d)\n", lock->l_pid); break;

    case F_WRLCK: printf("F_WRLCK (pid: %d)\n", lock->l_pid); break;

    default : break;

  }

}

 

void writelock(char *proсess, int fd, off_t from, off_t to)

{

  struct flock lock;

  lock.l_type = F_WRLCK;

  lock.l_start=from;

  lock.l_whence = SEEK_SET;

  lock.l_len=to;

  lock.l_pid = getpid();

  if (fcntl(fd, F_SETLKW, &lock) < 0)

  {

    printf("%s : fcntl(fd, F_SETLKW, F_WRLCK) failed (%s)\n",

    proсess,strerror(errno));

    printf("\nВозник DEADLOCK (%s - proсess)!!!!!!!!!\n\n",proсess);

    exit(0);

  }

  else

    printf("%s : fcntl(fd, F_SETLKW, F_WRLCK) успешно\n",proсess);

  status(&lock);

}

 

int main()

{

  int fd, i;

  pid_t pid;

  if(( fd=creat("dead.txt", S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))<0)

  {

    fprintf(stderr, "Ошибка при создании......\n");

    exit(0);

  }

  /*Заполняем dead.txt 50 байтами символа X*/

  for(i=0; i<50; i++)

    write(fd, "X", 1);

  if((pid = fork()) < 0)

  {

    fprintf(stderr, "Ошибка fork()......\n");

    exit(0);

  }

  else if(pid == 0) //Потомок

  {

    writelock("Потомок", fd, 20, 0);

    sleep(3);

    writelock("Потомок" , fd, 0, 20);

  }

  else //Родитель

  {

    writelock("Родитель", fd, 0, 20);

    sleep(1);

    writelock ("Родитель", fd, 20, 0);

  }

  exit(0);

}

Рис. 16. Программа, содержащая тупик.

Вначале создается файл данных dead.txt, в который записывается 50 символов X. Затем родительский процесс организует блокировку от байта 0 до байта 19, а потомок - блокировку от байта 20 до конца файла (EOF). Потомок засыпает на 3 сек., а родитель теперь устанавливает блокировку от байта 20 до байта EOF и при приостанавливается, так как байты от 20 до EOF блокированы в данный момент потомком, и используется команда F_SETLKW. Наконец, потомок пытается установить блокировку на запись от байта 0 до байта 19, причем он также приостанавливается, так как в этой области уже существует блокировка родителя и используется команда F_SETLKW. Здесь возникает тупик, что подтверждается выдачей кода ошибки для errno = EDEADLK (возникновение тупика по ресурсам). Тупик может возникнуть только при использовании команды F_SETLKW. Если применять команду F_SETLK, код ошибки для errno = EAGAIN (Ресурс временно недоступен).


next up previous contents
Next: Очереди сообщений. Up: Блокировка файлов. Previous: Режимы блокировки.   Contents
2003-12-09



Спонсоры:
Inferno Solutions
Hosting by Hoster.ru
Хостинг:

Закладки на сайте
Проследить за страницей
Created 1996-2022 by Maxim Chirkov
Добавить, Поддержать, Вебмастеру