iOS中的线程锁

2020-03-12  本文已影响0人  MiniCoder

pthread_mutex_t
NSLock
NSRecursiveLock
NSCondition
NSConditionLock
@synchronized
os_unfair_lock_t
atomic

关于线程锁的定义

Mutex(互斥锁)
pthread_mutex_t

A mutually exclusive (or mutex) lock acts as a protective barrier around a resource. A mutex is a type of semaphore that grants access to only one thread at a time. If a mutex is in use and another thread tries to acquire it, that thread blocks until the mutex is released by its original holder. If multiple threads compete for the same mutex, only one at a time is allowed access to it.
互斥(或互斥)锁充当资源周围的保护屏障。 互斥量是一种信号量,一次只授予对一个线程的访问权。 如果一个互斥对象正在使用中,而另一个线程试图获取它,那么该线程就会阻塞,直到互斥对象被其原始持有者释放。 如果多个线程竞争同一个互斥对象,则一次只允许访问一个互斥对象。

Recursive lock(递归锁)
@synchronized
NSRecursiveLock

A recursive lock is a variant on the mutex lock. A recursive lock allows a single thread to acquire the lock multiple times before releasing it. Other threads remain blocked until the owner of the lock releases the lock the same number of times it acquired it. Recursive locks are used during recursive iterations primarily but may also be used in cases where multiple methods each need to acquire the lock separately.
递归锁是互斥锁的一种变体。 递归锁允许单个线程在释放锁之前多次获取锁。 其他线程一直处于阻塞状态,直到锁的所有者释放该锁的次数与获取该锁的次数相同。 递归锁主要在递归迭代过程中使用,但也可以用于需要分别获取锁的多个方法的情况。

Read-write lock(读写锁)

A read-write lock is also referred to as a shared-exclusive lock. This type of lock is typically used in larger-scale operations and can significantly improve performance if the protected data structure is read frequently and modified only occasionally. During normal operation, multiple readers can access the data structure simultaneously. When a thread wants to write to the structure, though, it blocks until all readers release the lock, at which point it acquires the lock and can update the structure. While a writing thread is waiting for the lock, new reader threads block until the writing thread is finished. The system supports read-write locks using POSIX threads only. For more information on how to use these locks, see the pthread man page.
读写锁也称为共享排他锁。 这种类型的锁通常用于较大规模的操作,如果频繁地读取受保护的数据结构并且只是偶尔地修改它,则可以显著地提高性能。 在正常操作过程中,多个读取器可以同时访问数据结构。 但是,当一个线程想要写入结构时,它会阻塞,直到所有读取器释放锁,此时它会获得锁并更新结构。 当写入线程等待锁时,新的读线程会阻塞,直到写入线程完成。 该系统仅使用 POSIX 线程支持读写锁。 有关如何使用这些锁的详细信息,请参阅 pthread 手册页。

Distributed lock(分布式锁)

A distributed lock provides mutually exclusive access at the process level. Unlike a true mutex, a distributed lock does not block a process or prevent it from running. It simply reports when the lock is busy and lets the process decide how to proceed.
分布式锁在进程级别提供互斥访问。 与真正的互斥对象不同,分布式锁不会阻塞进程或阻止其运行。 它只是报告锁何时处于忙碌状态,并让进程决定如何继续。

Spin lock(旋转锁)
atomic

A spin lock polls its lock condition repeatedly until that condition becomes true. Spin locks are most often used on multiprocessor systems where the expected wait time for a lock is small. In these situations, it is often more efficient to poll than to block the thread, which involves a context switch and the updating of thread data structures. The system does not provide any implementations of spin locks because of their polling nature, but you can easily implement them in specific situations. For information on implementing spin locks in the kernel, see Kernel Programming Guide.
旋转锁反复轮询其锁定状态,直到该状态变为真实。 自旋锁通常用于多处理器系统,因为预期的锁等待时间很短。 在这些情况下,轮询通常比阻塞线程更有效,这涉及到上下文切换和线程数据结构的更新。 由于自旋锁的轮询性质,系统不提供任何自旋锁的实现,但是您可以轻松地在特定情况下实现它们。 有关在内核中实现自旋锁的信息,请参阅内核编程指南。

Double-checked lock(双重检查锁)

A double-checked lock is an attempt to reduce the overhead of taking a lock by testing the locking criteria prior to taking the lock. Because double-checked locks are potentially unsafe, the system does not provide explicit support for them and their use is discouraged.
双重检查锁试图通过在获取锁之前测试锁定条件来减少获取锁的开销。 由于双重检查的锁具有潜在的不安全性,因此系统不提供对它们的显式支持,并且不鼓励使用它们。

pthread_mutex_t

互斥锁的使用过程中,主要有pthread_mutex_init,pthread_mutex_destory,pthread_mutex_lock,pthread_mutex_unlock这几个函数以完成锁的初始化,锁的销毁,上锁和释放锁操作
如果是OC开发,并把pthread_mutex_t作为属性的话,要使用assign,因为pthread_mutex_t是一个结构体。
声明一个互斥锁

pthread_mutex_t _lock;
  //初始化
pthread_mutex_init(&_lock, NULL);

2.上锁 解锁

//上锁
pthread_mutex_lock(&_lock)
//这里加入可能产生死锁的操作 比如像文件写入  读取之类
//解锁 
pthread_mutex_unlock(&_lock)

2.释放锁

pthread_mutex_destroy(&_lock)

@synchronized

synchronized内部实现是一个递归锁。
关于 @synchronized,这儿比你想知道的还要多
正确使用多线程同步锁@synchronized()

优先级反转问题
具体来说,如果一个低优先级的线程获得锁并访问共享资源,这时一个高优先级的线程也尝试获得这个锁,它会处于 spin lock 的忙等状态从而占用大量 CPU。此时低优先级线程无法与高优先级线程争夺 CPU 时间,从而导致任务迟迟完不成、无法释放 lock。这并不只是理论上的问题,libobjc 已经遇到了很多次这个问题了,于是苹果的工程师停用了 OSSpinLock。OSSpinLock 的问题

NS系列锁

NS系列锁指的是NSLock、NSCondition、NSConditionLock、NSRecursiveLock,之所以把这几个放在一起,是因为它们都遵守NSLocking协议,就俩方法,加锁解锁,so easy!

@protocol NSLocking
- (void)lock;
- (void)unlock;
@end
@interface NSLock : NSObject <NSLocking> {
@private
    void *_priv;
}
- (BOOL)tryLock;
- (BOOL)lockBeforeDate:(NSDate *)limit;

@property (nullable, copy) NSString *name API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));

@end

方法说明:
trylock:能加锁返回 YES 并执行加锁操作,相当于 lock,反之返回 NO
lockBeforeDate:这个方法表示会在传入的时间内尝试加锁,若能加锁则执行加锁操作并返回 YES,反之返回 N

@interface NSConditionLock : NSObject <NSLocking> {
@private
    void *_priv;
}
- (instancetype)initWithCondition:(NSInteger)condition NS_DESIGNATED_INITIALIZER;
@property (readonly) NSInteger condition;
- (void)lockWhenCondition:(NSInteger)condition;
- (BOOL)tryLock;
- (BOOL)tryLockWhenCondition:(NSInteger)condition;
- (void)unlockWithCondition:(NSInteger)condition;
- (BOOL)lockBeforeDate:(NSDate *)limit;
- (BOOL)lockWhenCondition:(NSInteger)condition beforeDate:(NSDate *)limit;

@property (nullable, copy) NSString *name API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));
@end

NSConditionLock和NSLock类似,参数多了一个condition; 加锁时 lockWhenCondition、tryLockWhenCondition,只有 condition 参数与初始化时候的 condition 相等,lock 才能正确进行加锁操作; 解锁 unlockWithCondition,并不是condition符合条件才解锁,而是解锁时修改condition的值

NSConditon *condition =[ [NSCondition alloc]]init;

[condition lock];//一般用于多线程同时访问、修改同一个数据源,保证在同一时间内数据源只被访问、修改一次,其他线程的命令需要在lock 外等待,只到unlock ,才可访问

[condition unlock];//与lock 同时使用

[condition wait];//让当前线程处于等待状态

[condition signal];//CPU发信号告诉线程不用在等待,可以继续执行

这是我的验证代码,应该可以理解。

-(void)buttonClick{
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        NSLog(@"第1个方法");
        [self.condition lock];
        if (!self.tickets) {
            NSLog(@"数组不存在等待创建");
            [self.condition wait];
        }
        NSLog(@"数组创建完成 %lu",(unsigned long)self.tickets.count);
        self.tickets = nil;
        [self.condition unlock];
        
    });
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3ull * NSEC_PER_SEC)), dispatch_get_global_queue(0, 0), ^{
        NSLog(@"第二个方法");
        [self.condition lock];
         self.tickets = [NSMutableArray array];
         NSLog(@"数组创建完成");
         [self.condition signal];
         [self.condition unlock];
         
    });
}
[18804:1274440] 第1个方法
[18804:1274440] 数组不存在等待创建
[18804:1274439] 第二个方法
[18804:1274439] 数组创建完成
[18804:1274440] 数组创建完成 0
os_unfair_lock_t unfairLock;     
unfairLock = &(OS_UNFAIR_LOCK_INIT);     
os_unfair_lock_lock(unfairLock);     
os_unfair_lock_unlock(unfairLock);

内容未更新完,后续更新....

上一篇下一篇

猜你喜欢

热点阅读