iOS项目实践中的学习

多线程的那些锁

2019-05-08  本文已影响7人  coderhlt

一、OSSpinLock

自旋锁: 等待锁的线程会处于忙等(busy-wait)状态,一直占着CPU的资源。(假如有A、B、C三个线程,A第一个获得锁,B、C三个线程将处循环等待,然后不断的判断锁是否能够被成功获取,直到获取到锁才会退出循环)

导入头文件#import <libkern/OSAtomic.h>
// 初始化锁
OSSpinLock lock = OS_SPINLOCK_INIT;

// 加锁
OSSpinLockLock(&_lock);

加锁 和 解锁 中间放 多个线程访问的资源

// 解锁
OSSpinLockUnlock(&_lock);

二、os_unfair_lock

互斥锁:等待的线程会处于休眠状态。

#import "ViewController.h"
#import <os/lock.h>
@interface ViewController (){
    os_unfair_lock lock;
}
@property (assign, nonatomic) int ticketsCount;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
 
    lock = OS_UNFAIR_LOCK_INIT;
    
    
    [self ticketTest];
    
    
}

- (void)saleTicket
{
    os_unfair_lock_lock(&lock);
    
    int oldTicketsCount = self.ticketsCount;
    sleep(.2);
    oldTicketsCount--;
    self.ticketsCount = oldTicketsCount;
    NSLog(@"还剩%d张票 - %@", oldTicketsCount, [NSThread currentThread]);
    
    // 解锁
    os_unfair_lock_unlock(&lock);
}
- (void)ticketTest
{
    self.ticketsCount = 15;
    
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    
    dispatch_async(queue, ^{
        for (int i = 0; i < 5; i++) {
            [self saleTicket];
        }
    });
    
    dispatch_async(queue, ^{
        for (int i = 0; i < 5; i++) {
            [self saleTicket];
        }
    });
    
    dispatch_async(queue, ^{
        for (int i = 0; i < 5; i++) {
            [self saleTicket];
        }
    });
}

@end

三、pthread_mutex

#import "ViewController.h"
#import <pthread.h>
@interface ViewController ()
@property (assign, nonatomic) int ticketsCount;
@property(nonatomic,assign)pthread_mutex_t mutex;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
   // 初始化锁的属性
    pthread_mutexattr_t attr;
    pthread_mutexattr_init(&attr);
    pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
    
    //初始化锁
    pthread_mutex_init(&_mutex, &attr);
    
    //销毁锁的属性
    pthread_mutexattr_destroy(&attr);
    
    [self ticketTest];
    
    
}

- (void)saleTicket
{
    //加锁
    pthread_mutex_lock(&_mutex);
    int oldTicketsCount = self.ticketsCount;
    sleep(.2);
    oldTicketsCount--;
    self.ticketsCount = oldTicketsCount;
    NSLog(@"还剩%d张票 - %@", oldTicketsCount, [NSThread currentThread]);
    
    //解锁
    pthread_mutex_unlock(&_mutex);
}

//销毁锁
- (void)dealloc{

    pthread_mutex_destroy(&_mutex);
    
}

- (void)ticketTest
{
    self.ticketsCount = 15;
    
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    
    dispatch_async(queue, ^{
        for (int i = 0; i < 5; i++) {
            [self saleTicket];
        }
    });
    
    dispatch_async(queue, ^{
        for (int i = 0; i < 5; i++) {
            [self saleTicket];
        }
    });
    
    dispatch_async(queue, ^{
        for (int i = 0; i < 5; i++) {
            [self saleTicket];
        }
    });
}
@end

3.1、递归锁

#import "ViewController.h"
#import <pthread.h>
@interface ViewController ()
@property(nonatomic,assign)pthread_mutex_t mutex;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    //初始化锁
    pthread_mutex_init(&_mutex, NULL);

    [self test1];
   
}

- (void)test1{
    //加锁
    pthread_mutex_lock(&_mutex);
    
    NSLog(@"测试一");
    static int i = 0;
    I++;
    if (i<10) {
     [self test1];
    }
    //解锁
    pthread_mutex_unlock(&_mutex);
}

解决方案:设置为递归锁
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);

#import "ViewController.h"
#import <pthread.h>
@interface ViewController ()
@property (assign, nonatomic) int ticketsCount;
@property(nonatomic,assign)pthread_mutex_t mutex;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
   // 初始化锁的属性
    pthread_mutexattr_t attr;
    pthread_mutexattr_init(&attr);
    pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
    
    //初始化锁
    pthread_mutex_init(&_mutex, &attr);
    
    //销毁锁的属性
    pthread_mutexattr_destroy(&attr);
 
    [self test1];
  
}

- (void)test1{
    //加锁
    pthread_mutex_lock(&_mutex);
    
    NSLog(@"测试一");
    static int i = 0;
    I++;
    if (i<10) {
     [self test1];
    }
    //解锁
    pthread_mutex_unlock(&_mutex);
    
}

3.1、条件

屏幕快照 2019-05-08 下午4.12.04.png

需求描述:开启两个线程,线程一给可变的array删除最后一个元素,线程二给可变的array添加元素。如果array.count = 0则不需要删除元素。

#import "ViewController.h"
#import <pthread.h>
@interface ViewController ()
@property(nonatomic,strong)NSMutableArray *array;
@property(nonatomic,assign)pthread_mutex_t mutex;
@property(nonatomic,assign)pthread_cond_t condtion;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.array = [NSMutableArray array];
    
    //初始化条件
    pthread_cond_init(&_condtion, NULL);
    
    //初始化锁
    pthread_mutex_init(&_mutex, NULL);
    
    [[[NSThread alloc]initWithTarget:self selector:@selector(removeData) object:nil]start];
    
    sleep(2);
    
    [[[NSThread alloc]initWithTarget:self selector:@selector(addData) object:nil]start];

}

- (void)removeData{
    //加锁
    pthread_mutex_lock(&_mutex);
    NSLog(@"remove");
    if (self.array.count == 0) {
        pthread_cond_wait(&_condtion, &_mutex);
    }
    [self.array removeLastObject];
    NSLog(@"删除元素");
    pthread_mutex_unlock(&_mutex);
    
}

- (void)addData{

    //加锁
    pthread_mutex_lock(&_mutex);

    [self.array addObject:@"0"];
    
    NSLog(@"添加元素");

    pthread_cond_signal(&_condtion);
    
    //解锁
    pthread_mutex_unlock(&_mutex);
}

屏幕快照 2019-05-08 下午4.23.00.png

当 线程一执行了第43行: pthread_cond_wait(&_condtion, &_mutex);这句代码,线程一会放开锁进入休眠等待状态,线程二就可以获得锁进行加锁。当线程二执行了 pthread_cond_signal(&_condtion);这句代码后,线程一会被唤醒再次加上锁,开始从第45行代码之后继续执行。因此不管怎么样打印的结果都是先添加元素,再删除元素。总结来说pthread_mutex的应用场景应该是线程依赖。

四、OC版的锁

4.1、 NSLock

屏幕快照 2019-05-09 上午9.48.45.png
#import <Foundation/NSObject.h>
#import "ViewController.h"
@interface ViewController ()
@property(nonatomic,assign)int ticketsCount;
@property(nonatomic,strong)NSLock *lock;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    

    self.lock = [[NSLock alloc]init];
    
    [self ticketTest];
    
}
- (void)saleTicket
{
  //加锁
    [self.lock lock];
    
    int oldTicketsCount = self.ticketsCount;
    sleep(.2);
    oldTicketsCount--;
    self.ticketsCount = oldTicketsCount;
    NSLog(@"还剩%d张票 - %@", oldTicketsCount, [NSThread currentThread]);

     //解锁
    [self.lock unlock];
}


- (void)ticketTest
{
    self.ticketsCount = 15;

    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);

    dispatch_async(queue, ^{
        for (int i = 0; i < 5; i++) {
            [self saleTicket];
        }
    });

    dispatch_async(queue, ^{
        for (int i = 0; i < 5; i++) {
            [self saleTicket];
        }
    });

    dispatch_async(queue, ^{
        for (int i = 0; i < 5; i++) {
            [self saleTicket];
        }
    });
}

4.2、NSRecursiveLock

#import "ViewController.h"
@interface ViewController ()
@property(nonatomic,strong)NSRecursiveLock *recursiveLock;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    

    self.recursiveLock = [[NSRecursiveLock alloc]init];
    
    [self test1];
    
}
- (void)test1{
    //加锁
    [self.recursiveLock lock];
    
    NSLog(@"测试一");
    static int i = 0;
    I++;
    if (i<10) {
        [self test1];
    }
    //解锁
    [self.recursiveLock unlock];
}

4.3、NSCondition

屏幕快照 2019-05-09 上午9.49.07.png
#import "ViewController.h"
@interface ViewController ()
@property(nonatomic,strong)NSMutableArray *array;
@property(nonatomic,assign)int ticketsCount;
@property(nonatomic,strong)NSCondition *condition;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    

    self.array = [NSMutableArray array];

    self.condition = [[NSCondition alloc]init];
    
    
    [[[NSThread alloc]initWithTarget:self selector:@selector(removeData) object:nil]start];
    
    sleep(2);
    
    [[[NSThread alloc]initWithTarget:self selector:@selector(addData) object:nil]start];

    
}

- (void)removeData{
    [self.condition lock];
    NSLog(@"remove");
    if (self.array.count == 0) {
        [self.lockcondition wait];
    }
    [self.array removeLastObject];
    NSLog(@"删除元素");
   [self.condition unlock];
    
}

- (void)addData{
    
    [self.condition lock];
    [self.array addObject:@"0"];
    
    NSLog(@"添加元素");
   
    [self.condition signal];

    [self.condition unlock];
}

4.4、NSConditionLock

屏幕快照 2019-05-09 上午9.51.21.png
#import "ViewController.h"
@interface ViewController ()
@property(nonatomic,strong)NSConditionLock *conditionlock;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.conditionlock = [[NSConditionLock alloc]initWithCondition:1];

    [self test];
    
}
- (void)test{
 
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    
    dispatch_async(queue, ^{
        [self.conditionlock lockWhenCondition:2];
        
        NSLog(@"线程2");
        
        [self.conditionlock unlock];
        
    });
    
    sleep(10);
    dispatch_async(queue, ^{
        [self.conditionlock lockWhenCondition:1];
        
        NSLog(@"线程1");
        
        [self.conditionlock unlockWithCondition:2];
    });
    
}
屏幕快照 2019-05-09 下午3.52.53.png
上一篇下一篇

猜你喜欢

热点阅读