互斥锁和自旋锁

2019-08-13  本文已影响0人  ImmortalSummer

当多个线程访问同一个变量时, 很容易引发数据安全问题. 可以添加 互斥锁或者自旋锁解决这个问题.

自旋锁
当一个线程获取这个锁以后, 其他线程会抑制循环在哪里查看该锁是否被释放, 该锁不适合用于锁定保持时间过长的情况, 且消耗较大的性能.

互斥锁
当一个线程获得这个锁以后, 其他线程会被阻塞, 知道该锁被释放.

原子属性
atmoic/nonatmoic

atmoic:原子属性,为系统默认的属性,会为修饰的成员变量的setter方法自动加锁(自旋锁),使得线程安全,但较为消耗资源,效率相对低些。是一种单写多度的多线程技术,可能出现脏数据。

nonatomic:非原子属性,开发中最常用的属性,不会为修饰的成员变量的setter方法加锁,虽然线程不安全,但效率高.

互斥锁示例:

@interface ViewController (){
    int index;
}

//...

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        [self testLock:@"a"];
    });
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        [self testLock:@"b"];
    });
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        [self testLock:@"c"];
    });
}

-(void)testLock:(NSString *)flag{
    NSLog(@"flag:%@ 当前线程:%@",flag,[NSThread currentThread]);
    
    @synchronized (@"token") {
        for (int i=0; i<3; i++) {
            index++;
            sleep(0.1);
            NSLog(@"flag:%@ %d", flag, index);
        };
    }
}

-(void)testUnlock:(NSString *)flag{
    NSLog(@"flag:%@ 当前线程:%@",flag,[NSThread currentThread]);
    
    for (int i=0; i<3; i++) {
        index++;
        sleep(0.1);
        NSLog(@"flag:%@ %d", flag, index);
    };
}

/* 加锁 testLock 运行结果
2019-08-13 10:55:32.382984+0800 自旋锁和互斥锁[96408:4773768] flag:c 当前线程:<NSThread: 0x600002a7c600>{number = 5, name = (null)}
2019-08-13 10:55:32.383005+0800 自旋锁和互斥锁[96408:4773766] flag:a 当前线程:<NSThread: 0x600002a2be80>{number = 3, name = (null)}
2019-08-13 10:55:32.383020+0800 自旋锁和互斥锁[96408:4773769] flag:b 当前线程:<NSThread: 0x600002a07f40>{number = 4, name = (null)}
2019-08-13 10:55:32.383308+0800 自旋锁和互斥锁[96408:4773768] flag:c 1
2019-08-13 10:55:32.383444+0800 自旋锁和互斥锁[96408:4773768] flag:c 2
2019-08-13 10:55:32.383612+0800 自旋锁和互斥锁[96408:4773768] flag:c 3
2019-08-13 10:55:32.383771+0800 自旋锁和互斥锁[96408:4773769] flag:b 4
2019-08-13 10:55:32.383909+0800 自旋锁和互斥锁[96408:4773769] flag:b 5
2019-08-13 10:55:32.384102+0800 自旋锁和互斥锁[96408:4773769] flag:b 6
2019-08-13 10:55:32.384352+0800 自旋锁和互斥锁[96408:4773766] flag:a 7
2019-08-13 10:55:32.384701+0800 自旋锁和互斥锁[96408:4773766] flag:a 8
2019-08-13 10:55:32.385032+0800 自旋锁和互斥锁[96408:4773766] flag:a 9
*/
/* 不加锁 testUnlock 运行结果
2019-08-13 10:55:58.147531+0800 自旋锁和互斥锁[96415:4774371] flag:c 当前线程:<NSThread: 0x6000022b7940>{number = 4, name = (null)}
2019-08-13 10:55:58.147584+0800 自旋锁和互斥锁[96415:4774370] flag:b 当前线程:<NSThread: 0x6000022943c0>{number = 5, name = (null)}
2019-08-13 10:55:58.147586+0800 自旋锁和互斥锁[96415:4774372] flag:a 当前线程:<NSThread: 0x600002290380>{number = 3, name = (null)}
2019-08-13 10:55:58.147786+0800 自旋锁和互斥锁[96415:4774372] flag:a 3
2019-08-13 10:55:58.147786+0800 自旋锁和互斥锁[96415:4774370] flag:b 3
2019-08-13 10:55:58.147787+0800 自旋锁和互斥锁[96415:4774371] flag:c 3
2019-08-13 10:55:58.147914+0800 自旋锁和互斥锁[96415:4774372] flag:a 4
2019-08-13 10:55:58.147953+0800 自旋锁和互斥锁[96415:4774370] flag:b 5
2019-08-13 10:55:58.147986+0800 自旋锁和互斥锁[96415:4774371] flag:c 6
2019-08-13 10:55:58.148256+0800 自旋锁和互斥锁[96415:4774372] flag:a 7
2019-08-13 10:55:58.148509+0800 自旋锁和互斥锁[96415:4774371] flag:c 8
2019-08-13 10:55:58.149224+0800 自旋锁和互斥锁[96415:4774370] flag:b 9
*/

NSLock

@interface ViewController (){
    NSLock *lock;
}

-(void)testNSLock:(NSString *)flag{
    NSLog(@"flag:%@ 当前线程:%@",flag,[NSThread currentThread]);
    
    //多个线程要用同一个锁
    if (!lock) {
        lock = [NSLock new];
    }
    
    [lock lock];
    for (int i=0; i<3; i++) {
        index++;
        sleep(0.1);
        NSLog(@"flag:%@ %d", flag, index);
    };
    [lock unlock];
}

自旋锁示例:(失败的)

#import <os/lock.h>

os_unfair_lock_t unfairLock = &(OS_UNFAIR_LOCK_INIT);
os_unfair_lock_lock(unfairLock);
//lock coding 要加锁的代码
os_unfair_lock_unlock(unfairLock);
#import <libkern/OSAtomic.h>

OSSpinLock lock = OS_SPINLOCK_INIT;
OSSpinLockLock(&lock);
//lock coding 要加锁的代码
OSSpinLockUnlock(&lock);

//OSSpinLock ios10开始过期了

自旋锁搞了搞几次都不成, 反正性能也不好, 不用了哈哈哈

上一篇下一篇

猜你喜欢

热点阅读