2014-12-29 3 views
2

Мне нужно правильно обработать EDEADLK. В моей программе я вижу, что оба ребенка ждут, пока родитель не спал, а затем они применили блокировку, и сразу они покидают ее. Извините за свои ошибки, я испанский студент.Почему я не вижу тупик (EDEADLK), когда несколько процессов блокируют один и тот же fd с F_SETLKW?

int main(){ 

    pid_t childpid, childpid2; 

    struct flock cerrojo; 
    int fd, status; 

    if ((fd=open("prueba", O_RDWR)) == -1) 
     perror("apertura fallo"); 

    cerrojo.l_type =F_WRLCK; 
    cerrojo.l_whence =SEEK_SET; 
    cerrojo.l_start =0; 
    cerrojo.l_len =0; 

    if (fcntl(fd, F_SETLK,&cerrojo) == -1) 
     perror("cerrojo fallo"); 

    if ((childpid= fork()) == -1) { 
     printf("Could not create child"); 
     exit(-1); 
    } 

    if(childpid){ 

     if ((childpid2= fork()) == -1) { 
      printf("Could not create child"); 
      exit(-1); 
     } 

     if(childpid2){ 

      cerrojo.l_type = F_UNLCK; 
      cerrojo.l_whence =SEEK_SET; 
      cerrojo.l_start =0; 
      cerrojo.l_len =0; 

      sleep(2); 

      fcntl(fd, F_SETLKW, &cerrojo); 

      waitpid(childpid,&status,0); 
      waitpid(childpid2,&status,0); 

     } 


    } 

    if(!childpid||!childpid2){ 

     printf("Soy el hijo %d\n",getpid()); 

     if(fcntl(fd, F_SETLKW,&cerrojo) == -1){ 
      printf("FCNTL FALLA EN PID: %d\n",getpid()); 
      sleep(1); 
     } 

     printf("PID %d va a quitar el cerrojo.\n",getpid()); 

     cerrojo.l_type = F_UNLCK; 
     cerrojo.l_whence =SEEK_SET; 
     cerrojo.l_start =0; 
     cerrojo.l_len =0; 

     fcntl(fd, F_SETLKW, &cerrojo); 

     printf("HIJO ACABADO\n"); 

    } 

    return 0; 

} 
+0

"Эта ошибка": _which_ ошибка? Чего вы ожидаете? Что происходит вместо этого? Вы пытались проследить программу ('strace -f')? Что вы видите? –

+0

Мне нужно заставить edeadlk посмотреть, как ядро ​​избежать тупика. –

+0

По крайней мере, дайте нам представление о том, что происходит, как это отличается от ваших ожиданий. В linux'strace -r -f -etrace = fcntl <ваша программа> 'даст много информации, но даже просто выход вашей программы поможет :-) –

ответ

0

Для тупиковой вам нужно по крайней мере два замки. Я всегда предполагаю, что я заперт в комнате А, с ключом комнаты В и с кем-то в комнате В, с ключом комнаты А.

В вашем примере только один замок: обе дети пытаются запереть такая же большая «дверь» (весь файл). Второй, кто попадет туда, будет блокироваться до тех пор, пока первый релиз блокировки не будет снова, а затем спеть ту же песню litle Заблокировать, спать, ... разблокировать. Никакой тупик в поле зрения.

Теперь, в приведенном ниже примере, родительские замки две «двери» - первый и второй байт файла fd указывает на (? Кстати, это действительно необходимо для вашего примера), а затем нерестится двух детей. Оба ребенка пытаются заблокировать оба байта, но каждый начинается с другого. Как только родитель выпускает оба байта, дети приобретают свои блокировки, 4 попытки блокировки во всех, но последний из них вызывает тупик и должным образом терпит неудачу с EDEADLK, так что каждый будет жить счастливо, благодаря нашему мудрую и простому ядру.

#include <stdio.h> 
#include <unistd.h> 
#include <fcntl.h> 
#include <stdlib.h> 
#include <string.h> 
#include <errno.h> 

int main(){ 

    pid_t childpid, childpid2; 

    struct flock cerrojo; 
    int fd, status; 

    if ((fd=open("prueba", O_RDWR)) == -1) 
     perror("apertura fallo"); 

    cerrojo.l_type = F_WRLCK; 
    cerrojo.l_whence = SEEK_SET; 
    cerrojo.l_start = 0; 
    cerrojo.l_len = 2; /* lock "doors" (i.e. bytes) 0 and 1*/ 

    if (fcntl(fd, F_SETLK,&cerrojo) == -1) 
     perror("cerrojo fallo"); 


    if((childpid= fork())){ /* parent */ 
     if ((childpid2= fork())) { /* still parent */ 

      cerrojo.l_type = F_UNLCK; 
      cerrojo.l_len = 2; /* unlock both doors: let the fun begin :-) */ 

      sleep(2); 
      printf("Tata va a quitar el cerrojo....\n",getpid()); 
      fcntl(fd, F_SETLKW, &cerrojo); 

      waitpid(childpid,&status,0); 
      waitpid(childpid2,&status,0); 
     } 
    } 

    if(!childpid||!childpid2){ /* in child 1 or child 2 */ 

     printf("Soy el hijo %d\n",getpid()); 

     int offset0 = (childpid ? 0 : 1); /* child1 gets 0 and 1, child 2 gets 1 and 0 */ 
     int offset1 = (childpid ? 1 : 0); 
     cerrojo.l_len = 1; 


     cerrojo.l_start = offset0; /* lock door 0 (1) as soon as parent lets us*/ 
     printf("PID %d locking byte %d\n", getpid(), offset0); 
     if(fcntl(fd, F_SETLKW,&cerrojo) == -1){ 
      printf("CERROJO byte %d FALLA EN PID %d (%s)\n",offset0, getpid(), strerror(errno)); 
     } 

     sleep(1); /* guarantee that the other child has our next door locked ... */ 
     printf("PID %d locking byte %d\n", getpid(), offset1); 
     cerrojo.l_start = offset1; /* lock door 1 (0). The second of both children who gets here closes the circle and faces deadlock */ 
     if(fcntl(fd, F_SETLKW,&cerrojo) == -1){ 
      printf("CERROJO byte %d FALLA EN PID: %d (%s)\n", offset1, getpid(), strerror(errno)); 
     } 

     printf("HIJO %d ACABADO (releasing its lock)\n", getpid()); /* Falling off the end of main() will release the lock anyway */ 

    } 
} 

Выход:

[[email protected]] ~ > ./test     
Soy el hijo 29711 
PID 29711 locking byte 1 
Soy el hijo 29712 
PID 29712 locking byte 0 
Tata va a quitar el cerrojo.... 
PID 29711 locking byte 0 
PID 29712 locking byte 1 
CERROJO byte 1 FALLA EN PID: 29712 (Resource deadlock avoided) 
HIJO 29712 ACABADO (releasing its lock) 
HIJO 29711 ACABADO (releasing its lock) 
+0

Это именно то, что я хотел. Большое спасибо: D –

 Смежные вопросы

  • Нет связанных вопросов^_^