ios開發中的幾種鎖(二)

版本記錄

版本號 時間
V1.0 2017.05.21

前言

ios中有好幾種鎖,比如自旋鎖,互斥鎖,信號量等等,鎖其實是多線程數據安全的一種解決方案,作用就是保證同一時間只有一個線程訪問和改變某些敏感數據,這些鎖的性能也是差別很大,最近看了幾個技術大牛的技術博客,我才發現我以前對鎖的理解太膚淺了,心虛的趕緊找資料又開始了深入學習,然后整理出來。前面介紹了幾種鎖:
1. ios開發中的幾種鎖(一)
這篇接著講其他的幾種鎖。

詳情

一、pthread_mutex 互斥鎖

ibireme在《不再安全的OSSpinLock》這篇文章中提到性能最好的OSSpinLock不再是線程安全的并把自己開源項目中的OSSpinLock都替換成了pthread_mutex。下面還是先看代碼。

1. JJPtheadVC.h

#import <UIKit/UIKit.h>

@interface JJPtheadVC : UIViewController

@end


2. JJPtheadVC.m
#import "JJPtheadVC.h"
#import <pthread.h>

@interface JJPtheadVC ()

@end

@implementation JJPtheadVC

#pragma mark - Override Base Function

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    //互斥所
    [self aboutPthreadMutex];
    
}

#pragma mark - Object Private Function

- (void)aboutPthreadMutex
{
    static pthread_mutex_t mutexLock;
    pthread_mutex_init(&mutexLock, NULL);
    NSInteger __block num = 10;
    
    //線程1
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        
        NSLog(@"線程1準備上鎖,%@",[NSThread currentThread]);
        pthread_mutex_lock(&mutexLock);
        num = num + 1;
        NSLog(@"線程1--num1=%ld",num);
        pthread_mutex_unlock(&mutexLock);
    });
    
    //線程2
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        
        NSLog(@"線程2準備上鎖,%@",[NSThread currentThread]);
        pthread_mutex_lock(&mutexLock);
        num = num + 1;
        NSLog(@"線程2--num2=%ld",num);
        pthread_mutex_unlock(&mutexLock);
    });

}

@end

查看結果

2017-05-20 13:27:14.675 lock[3995:185687] 線程2準備上鎖,<NSThread: 0x60800007e0c0>{number = 4, name = (null)}
2017-05-20 13:27:14.675 lock[3995:185685] 線程1準備上鎖,<NSThread: 0x600000265080>{number = 3, name = (null)}
2017-05-20 13:27:14.675 lock[3995:185687] 線程2--num2=11
2017-05-20 13:27:14.678 lock[3995:185685] 線程1--num1=12

注意:pthread_mutex 中也有個pthread_mutex_trylock(&pLock),和上面提到的 OSSpinLockTry(&oslock)區別在于,前者可以加鎖時返回的是 0,否則返回一個錯誤提示碼;后者返回的 YES和NO。


二、pthread_mutex(recursive) 遞歸鎖

根據上面講述的幾個鎖,可以發現:加鎖后只能有一個線程訪問該對象,后面的線程需要排隊,并且lock與unlock都是對應出現的,同一線程多次lock是不允許的,而遞歸鎖允許同一個線程在未釋放其擁有的鎖時反復對該鎖進行加鎖操作。

下面直接看代碼

1. JJPthreadRecursiveVC.h

#import <UIKit/UIKit.h>

@interface JJPthreadRecursiveVC : UIViewController

@end

2. JJPthreadRecursiveVC.m

#import "JJPthreadRecursiveVC.h"
#import <pthread.h>

@interface JJPthreadRecursiveVC ()

@end

@implementation JJPthreadRecursiveVC


#pragma mark - Override Base Function

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    //遞歸鎖
    [self aboutPthreadMutexRecursive];
    
}

#pragma mark - Object Private Function

- (void)aboutPthreadMutexRecursive
{
    static pthread_mutex_t pLock;
    pthread_mutexattr_t attr;
    //初始化attr并且給它賦予默認
    pthread_mutexattr_init(&attr);
    //設置鎖類型,這邊是設置為遞歸鎖
    pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
    pthread_mutex_init(&pLock, &attr);
    //銷毀一個屬性對象,在重新進行初始化之前該結構不能重新使用
    pthread_mutexattr_destroy(&attr);

    //1.線程1
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        static void (^RecursiveBlock)(int);
        RecursiveBlock = ^(int value) {
            pthread_mutex_lock(&pLock);
            if (value > 0) {
                NSLog(@"value = %d", value);
                NSLog(@"線程 = ,%@",[NSThread currentThread]);
                RecursiveBlock(value - 1);
            }
            pthread_mutex_unlock(&pLock);
        };
        RecursiveBlock(5);
    });
}

@end

直接看輸出結果

2017-05-21 17:29:14.341 lock[1271:55126] value = 5
2017-05-21 17:29:14.342 lock[1271:55126] 線程 = ,<NSThread: 0x60800006e440>{number = 3, name = (null)}
2017-05-21 17:29:14.342 lock[1271:55126] value = 4
2017-05-21 17:29:14.343 lock[1271:55126] 線程 = ,<NSThread: 0x60800006e440>{number = 3, name = (null)}
2017-05-21 17:29:14.343 lock[1271:55126] value = 3
2017-05-21 17:29:14.344 lock[1271:55126] 線程 = ,<NSThread: 0x60800006e440>{number = 3, name = (null)}
2017-05-21 17:29:14.344 lock[1271:55126] value = 2
2017-05-21 17:29:14.345 lock[1271:55126] 線程 = ,<NSThread: 0x60800006e440>{number = 3, name = (null)}
2017-05-21 17:29:14.348 lock[1271:55126] value = 1
2017-05-21 17:29:14.349 lock[1271:55126] 線程 = ,<NSThread: 0x60800006e440>{number = 3, name = (null)}

注意:上面的代碼如果我們用 pthread_mutex_init(&pLock, NULL) 初始化會出現死鎖的情況,遞歸鎖能很好的避免這種情況的死鎖。

相關參考技術博客

1.iOS 開發中的八種鎖(Lock)
2.不再安全的 OSSpinLock
3. NSRecursiveLock遞歸鎖的使用
4.關于dispatch_semaphore的使用
5.實現鎖的多種方式和鎖的高級用法

后記

剩下的幾種鎖,待續哦~~~~

思念
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 轉自(https://bestswifter.com/ios-lock/#) 深入理解 iOS 開發中的鎖 摘要 ...
    犯色戒的和尚閱讀 337評論 0 1
  • 鎖是一種同步機制,用于多線程環境中對資源訪問的限制iOS中常見鎖的性能對比圖(摘自:ibireme): iOS鎖的...
    LiLS閱讀 1,553評論 0 6
  • 前言 在多線程開發中,常會遇到多個線程訪問修改數據。為了防止數據不一致或數據污染,通常采用加鎖機制來保證線程安全。...
    趙夢楠閱讀 1,007評論 0 5
  • iOS開發中常用的幾種鎖 簡介: 操作系統在進行多線程調度的時候,為了保證多線程安全引入了鎖的機制,以實現指定代碼...
    sunnyxg0812閱讀 1,306評論 0 2
  • 線程安全是什么? 當一個線程訪問數據的時候,其他的線程不能對其進行訪問,直到該線程訪問完畢。簡單來講就是在同一時刻...
    6ffd6634d577閱讀 2,215評論 1 7