c语言 - 为什么当多个进程用F_SETLKW锁定同一个 fd 时,我看不到死锁 (EDEADLK)?



我需要正确处理 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 %dn",getpid());
        if(fcntl(fd, F_SETLKW,&cerrojo) == -1){ 
            printf("FCNTL FALLA EN PID: %dn",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 ACABADOn");
    }
    return 0;
}

对于死锁,您至少需要两个锁。我总是想象自己被锁在

房间A,用房间B的钥匙,而房间B的其他人,用房间A的钥匙。

在您的示例中,只有一个锁:两个孩子都尝试锁同一个大"门"(整个文件)。到达那里的第二个将阻止,直到第一个再次释放锁,然后唱同样的轻歌锁,睡觉,...解锁。看不到僵局。

现在,在下面的示例中,父级锁定了两个"门"——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 %dn",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 %dn", 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 %dn", 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)

相关内容

  • 没有找到相关文章

最新更新