• 解决NSDistributedLock进程互斥锁的死锁问题(一)


    在MAC下的多进程开发中,NSDistributedLock是一个非常方便的互斥锁解决方案,一般的使用方法:

    1
    2
    3
    4
    5
    6
    7
    8
    NSDistributedLock *lock = [[NSDistributedLock alloc] initWithPath:@"/Users/mac/Desktop/lock.lock"];
    while (![lock tryLock])
    {
    sleep(1);
    }

    //do something
    [lock unlock];

    但在实际使用过程中,当执行到do something时程序退出,程序再次启动之后tryLock就再也不能成功了,陷入死锁状态.这是使用NSDistributedLock时非常隐蔽的风险.其实要解决的问题就是如何在进程退出时会自动释放锁.
    在《Unix环境高级编程》中有对record locking(记录锁)的介绍,而这种锁的机制也是基于文件,但它的解锁条件刚好可以解决我们的问题,因为当进程退出时记录锁会自动释放所持有的锁.

    fcntl是Unix兼容最好的一种记录锁实现方案,关于它的接口描述在sys/fcntl.h内,函数原型是

    1
    int fcnt1(int filedes, int cmd, .../* struct flock *flockptr */);

    该函数用于记录锁时,cmd是F_GETLK、F_SETLK或F_SETLKW。第三个参数(称其为flockptr)是一个指向flock结构的指针。

    1
    2
    3
    4
    5
    6
    7
    struct flock {
    off_t l_start; /* starting offset */
    off_t l_len; /* len = 0 means until end of file */
    pid_t l_pid; /* lock owner */
    short l_type; /* lock type: read/write, etc. */
    short l_whence; /* type of l_start */
    };

    关于fcntl函数的三种命令描述:
    F_GETLK 取得文件锁定的状态。
    F_SETLK 设置文件锁定的状态。此时flcok 结构的l_type 值必须是F_RDLCK、F_WRLCK或F_UNLCK。如果无法建立锁定,则返回-1,错误代码为EACCES 或EAGAIN。
    F_SETLKW F_SETLK 作用相同,但是无法建立锁定时,此调用会一直等到锁定动作成功为止。若在等待锁定的过程中被信号中断时,会立即返回-1,错误代码为EINTR。

    用flock实现NSDistributedLock中tryLock:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    - (BOOL)tryLock
    {
    int fd = open(path, O_CREAT|O_RDWR,0666);
    if (fd < 0)
    {
    NSLog(@"[err] open fail: %s",strerror(errno));
    return NO;
    }

    struct flock lockinfo;
    lockinfo.l_type = F_WRLCK;
    lockinfo.l_whence = SEEK_SET;
    lockinfo.l_start = 0;
    lockinfo.l_len = 0;

    int re = fcntl(fd, F_SETLK, &lockinfo);
    if (re != 0)
    {
    close(fd);
    return NO;
    }
    return YES;
    }

    用flock实现NSDistributedLock中unlock:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    - (void)_unlock
    {
    struct flock lockinfo;
    lockinfo.l_type = F_UNLCK;
    lockinfo.l_whence = SEEK_SET;
    lockinfo.l_start = 0;
    lockinfo.l_len = 0;

    fcntl(fd, F_SETLK, &lockinfo);
    close(fd);
    }

    但需要注意的是fcntl实现的记录锁是不支持进程内的多线程间的互斥,为了解决这些问题并完整实现NSDistributedLock中的所有方法和实际表现,下面是我封装的QMDistributedLock:
    站内下载:QMDistributedLock.zip

  • 相关阅读:
    第八次作业
    设计一款给爸爸妈妈用的手机
    第五次作业
    第四次作业(项目分析)
    第二次作业(个人项目实践)
    即时通讯软件的发展演变
    C++用法的学习心得
    JavaScript(变量、作用域和内存问题)
    一、Java和JavaScript
    使用Hyper-V创建虚拟机
  • 原文地址:https://www.cnblogs.com/xiao-love-meng/p/5757598.html
Copyright © 2020-2023  润新知