在MAC下的多进程开发中,NSDistributedLock是一个非常方便的互斥锁解决方案,一般的使用方法:
1
|
NSDistributedLock *lock = [[NSDistributedLock alloc] initWithPath:@"/Users/mac/Desktop/lock.lock"];
|
但在实际使用过程中,当执行到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
|
struct flock {
|
关于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
|
- (BOOL)tryLock
|
用flock实现NSDistributedLock中unlock:
1
|
- (void)_unlock
|
但需要注意的是fcntl实现的记录锁是不支持进程内的多线程间的互斥,为了解决这些问题并完整实现NSDistributedLock中的所有方法和实际表现,下面是我封装的QMDistributedLock:
站内下载:QMDistributedLock.zip