The OpenNET Project / Index page

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

Каталог документации / Раздел "Программирование в Linux" / Оглавление документа
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), образуя тупик. Никакой из процессов не может возобновить свое выполнение.

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

Пример программы, вызывающей тупик:

#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) (%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);

}

Вначале создается файл данных 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
2004-06-22



Партнёры:
PostgresPro
Inferno Solutions
Hosting by Hoster.ru
Хостинг:

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