Chinaunix首页 | 论坛 | 博客
  • 博客访问: 265303
  • 博文数量: 74
  • 博客积分: 1470
  • 博客等级: 上尉
  • 技术积分: 793
  • 用 户 组: 普通用户
  • 注册时间: 2008-11-25 21:01
文章分类

全部博文(74)

文章存档

2011年(1)

2010年(32)

2009年(32)

2008年(9)

我的朋友

分类: C/C++

2009-12-25 13:28:35

其实记录锁的名字叫文件锁会比较贴切一点.因为其加锁和解锁都是通过对文件的操作完成的.文件锁的粒度大可到整个文件,小可到一个字节,长度可变.
记录锁分为共享读锁和独占写锁,前者也叫做共享锁后者也叫做排他锁.具体的加锁规则就不详细的介绍了.
这里只说明一点:
锁与进程和文件两方面有关系,它和前者关系是:当一个进程结束后,他对文件加的锁也就消失了.它和后者的关系是:当进程close文件描述符,切断文件和进程的联系进程所创建的锁也会消失.
直接上测试代码:

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

int main(int argc,char* argv[])
{
    int fd;
    struct flock lock;
    pid_t pid,w;
    int status;

    /*赋值lock结构体,加锁整个文件*/
    lock.l_whence = SEEK_SET;
    lock.l_start = 0;
    lock.l_len = 0;

    if((fd=open("/tmp/a",O_CREAT | O_TRUNC | O_RDWR,0777))<0) {
        fprintf(stderr,"file abc open error\n");
        fprintf(stderr,"%s\n",strerror(errno));
        exit(EXIT_FAILURE);
    }
    
    pid = fork();
    if(pid<0) {
        fprintf(stderr,"fork failed. %s\n",strerror(errno));
        exit(EXIT_FAILURE);
    }

    //son

    if(!pid)
    {
        while(1)
        {
            lock.l_type=F_WRLCK;
            if ((fcntl(fd, F_SETLK, &lock)) == 0){
                printf("write lock set by son %d\n", getpid());
                break;
            } else {
                fprintf(stderr, "son lock failed. %s\n",strerror(errno));
            }

            //cannot lock the file, get the lock.l_pid

            if ((fcntl(fd, F_GETLK, &lock)) == 0)
                printf("write lock already set by father %d\n", lock.l_pid);
            else
                fprintf(stderr, "cannot get the description of struck flock.%s\n",
                        strerror(errno));
            sleep(2);
        }
        printf("son running ....\n");
        sleep(5);
        //exit(0);


        //unlock the write lock

        lock.l_type=F_UNLCK;
        if ((fcntl(fd, F_SETLK, &lock)) == 0){
            printf("unlock by son %d\n", getpid());
            close(fd);
        } else {
            fprintf(stderr, "unlock error. %s\n",strerror(errno));
            exit(EXIT_FAILURE);
        }
        return 0;
    }

    //father

    sleep(10); //保证子进程先申请到锁

    while(1)
    {
        lock.l_type=F_WRLCK;
        if ((fcntl(fd, F_SETLK, &lock)) == 0){
            printf("write lock set by father %d\n", getpid());
            break;
        } else {
            fprintf(stderr, "father lock failed. %s\n",strerror(errno));
        }

        //cannot lock the file, get the lock.l_pid

        if ((fcntl(fd, F_GETLK, &lock)) == 0)
            printf("write lock already set by son %d\n", lock.l_pid);
        else
            fprintf(stderr, "cannot get the description of struck flock. %s\n",strerror(errno));

        sleep(2);
    }
    printf("father running ....\n");
    sleep(5);
    lock.l_type=F_UNLCK;

    //unlock

    if ((fcntl(fd, F_SETLK, &lock)) == 0){
        printf("unlock by father %d\n", getpid());
        close(fd);
    } else {
        fprintf(stderr, "unlock error. %s\n",strerror(errno));
        exit(EXIT_FAILURE);
    }

    //wait the son process

    w = waitpid(pid, &status, 0);
    if (w == -1) {
        perror("waitpid");
        exit(EXIT_FAILURE);
    }

    return 0;
}



$ gcc testfilelock.c
$ ./a.out
write lock set by son 13687
son running ....
father lock failed. Resource temporarily unavailable
write lock already set by son 13687
father lock failed. Resource temporarily unavailable
write lock already set by son 13687
father lock failed. Resource temporarily unavailable
write lock already set by son 13687
unlock by son 13687
write lock set by father 13686
father running ....
unlock by father 13686
可以看到子进程先申请了写锁,然后sleep了5秒,在此其间父进程申请写所示都会lock failed. Resource temporarily unavailable.一直等到子进程释放写锁后,父进程才申请成功.
现在把子进程中的exit(0)那一行的注释去掉,也就是说让子进程申请到写锁后退出,看是不是会自动释放锁.
$ gcc testfilelock.c
$ ./a.out
write lock set by son 15938
son running ....
father lock failed. Resource temporarily unavailable
write lock already set by son 15938
father lock failed. Resource temporarily unavailable
write lock already set by son 15938
father lock failed. Resource temporarily unavailable
write lock already set by son 15938
write lock set by father 15937
father running ....
unlock by father 15937

看来在子进程终止时系统会自动处理遗留下来的锁,这正是文件锁的最大的好处.

reference:

UNIX高级环境编程》第2 人民邮电出版社




阅读(1666) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~