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


    上一篇文章中介绍了采用了文件记录锁来实现更加安全的多进程互斥,它的平台兼容性也非常好,并且我们也采用它实现了NSDistributedLock的所有的方法.
    其实在OSX还可以采用文件读写锁来实现更加方便的进程互斥,在fcntl.h中我们可以看到这样的宏定义:

    1
    2
    3
    #if !defined(_POSIX_C_SOURCE) || defined(_DARWIN_C_SOURCE)
    #define O_SHLOCK 0x0010 /* open with shared file lock */
    #define O_EXLOCK 0x0020 /* open with exclusive file lock */

    这些宏是同O_RDONLY,O_WRONLY等一样,都是用于打开文件时使用的掩码,也就是说我们可以在open文件的时候加上这些掩码来实现读写互斥,具体的规则就是(适用于多进程或多线程):
    只要没有写模式下的加锁,就可以进行读模式下的加锁;
    只有读写锁处于不加锁状态时,才能进行写模式下的加锁;

    当然我们大多数情况下都只是简单的资源独占的互斥,所以直接采用写模式下的互斥便可,例如当进程A有如下执行了操作:

    1
    open(filepath, O_CREAT|O_EXLOCK,0666);

    其它进程再要做同样操作时就会进入阻塞状态,直到进程A中close了文件描述符或进程退出.

    因为同样适用于多线程,所以我们可以实现以下阻塞版本的NSDistributedLock:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    @interface QMDistributedLock : NSObject<NSLocking>
    {
    NSString *filePath;
    int fileID;
    }

    - (instancetype)initWithPath:(NSString *)path;

    @end

    @implementation QMDistributedLock

    - (instancetype)initWithPath:(NSString *)path
    {
    self = [super init];
    if (self)
    {
    filePath = [path copy];
    if (!filePath)
    return nil;

    NSFileManager *fileMgr = [NSFileManager defaultManager];
    NSString *parentPath = [filePath stringByDeletingLastPathComponent];

    //父目录不存在
    if (![fileMgr fileExistsAtPath:parentPath])
    return nil;

    //父目录不可写
    if (![fileMgr isWritableFileAtPath:parentPath])
    return nil;

    //已经存在该名字的目录
    BOOL isDirectory = NO;
    if ([fileMgr fileExistsAtPath:filePath isDirectory:&isDirectory] && isDirectory)
    {
    if (![fileMgr removeItemAtPath:filePath error:NULL])
    return nil;
    }
    }
    return self;
    }

    - (void)lock
    {
    fileID = open([filePath fileSystemRepresentation], O_CREAT|O_EXLOCK,0666);
    }

    - (void)unlock
    {
    close(fileID);
    }
  • 相关阅读:
    C# BackGroundWorker控件演示代码
    C#多线程池演示例程下载图片
    反流技术之IE插件技术研究第二部分
    C# 从剪贴板中读取HTML中的中文字符出现乱码问题的解决方案
    C#单线程演示程序带参数
    C# 中as和is的用法总结
    Delphi关于记录文件的操作
    用PowerDesigner创建Access数据库
    常用Delphi开发资料网址
    等待外部应用程序的执行结果
  • 原文地址:https://www.cnblogs.com/xiao-love-meng/p/5757602.html
Copyright © 2020-2023  润新知