Почему я не вижу тупик (EDEADLK), когда несколько процессов блокируют один и тот же файл с помощью F_SETLKW?
Мне нужно правильно обращаться с EDEADLK. В моей программе я вижу, что оба ребенка ждут, пока родитель спит, и затем они применяют блокировку и сразу же покидают ее. Извините за мои ошибки, я испанский студент.
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;
}
1 ответ
Для тупика нужно как минимум два замка. Я всегда представляю себя запертым в комнате А с ключом от комнаты В, а кто-то еще в комнате В с ключом от комнаты А.
В вашем примере есть только одна блокировка: оба потомка пытаются заблокировать одну и ту же большую "дверь" (весь файл). Второй, кто доберется туда, будет блокировать, пока первый снова не снимет блокировку, а затем споет ту же самую маленькую песню: Блокировка, сон,... разблокировка Никакого тупика не видно.
Теперь в приведенном ниже примере родитель блокирует две "двери" - первый и второй байт файла. 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 */
}
}
Выход:
[hlub@karpaten] ~ > ./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)