iOS線程安全-各類線程鎖測試和性能對比

1. @synchronized 關鍵字加鎖
2. NSLock 對象鎖
3. NSCondition 條件鎖1
4. NSConditionLock 條件鎖2
5. NSRecursiveLock 遞歸鎖
6. pthread_mutex 互斥鎖(C語言)
7. pthread_mutex(recursive) 互斥鎖(C語言)2-也是遞歸鎖一種類似NSConditionLock
8. dispatch_semaphore 信號量實現(xiàn)加鎖(GCD)
9. OSSpinLock 自旋鎖!H銮病:ぁ1渡荨=厍浮(已不安全)無法保證和控制優(yōu)先級不同的線程的調(diào)度,除非所有優(yōu)先級都是一樣的炸庞,而除非帶出來的話往往木有意義

一.不廢話直接貼代碼

GitHub地址:https://github.com/Yjunjie/MultithreadingAndLock/tree/master
基本都是根據(jù)實際情況設立的情境最欠,買票,網(wǎng)絡數(shù)據(jù)加載處理积担,網(wǎng)絡數(shù)據(jù)上傳處理等等陨晶。部分操作如圖:
1.多售票員賣票情境
http://upload-images.jianshu.io/upload_images/6285199-f054d3f3b9473816.gif?imageMogr2/auto-orient/strip

2017-06-15 16_25_31.gif

2.用戶路線緩存,經(jīng)緯度數(shù)據(jù)點上傳
http://upload-images.jianshu.io/upload_images/6285199-4c1eeabbe9ee3f3e.gif?imageMogr2/auto-orient/strip
2017-06-15 16_28_08.gif

3.各種鎖性能對比帝璧,都進行一千萬次加鎖空操作先誉。
這里需要做個簡要說明,本來就是毫秒級的操作的烁,在某些情況下受硬件影響褐耳,我分別用真機(5C,6,7P),模擬器都試了下,結果不一變化還蠻多渴庆。但是基本都和理論相差不大铃芦。主要get的結果就是

1.性能最佳:但是OSSpinLock 自旋鎖已經(jīng)不再安全,不推薦或者慎重使用
OSSpinLock 自旋鎖
dispatch_semaphore 信號量實現(xiàn)加鎖(GCD)
2.性能次之:NSLock貌似還比較折中襟雷,使用頻率貌似還蠻高
NSLock 對象鎖
NSCondition 條件鎖
3.耗時最長:正常情況下沒有例外過刃滓,不考怎么慮性能耗時那就@synchronized 關鍵字鎖
@synchronized 關鍵字鎖

各種鎖性能對比實際操作圖示如下:

IMG_3226.PNG

全部代碼

因為只是測試各類鎖的特性問題,我沒有一一處理耸弄,畢竟對比測試有個所以然就夠了咧虎,所以期間操作有些鎖的測試不能重復測試需要殺死程序重啟測試。


#ifdef DEBUG
#   define DEBUGLog(fmt, ...) NSLog((@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__);
#else
#   define DEBUGLog(...)
#endif
#define Screen_Width ([UIScreen mainScreen].bounds.size.width)
#define Screen_Height ([UIScreen mainScreen].bounds.size.height)

#import "ViewController.h"
#import <objc/runtime.h>
#import <pthread.h>
#import <libkern/OSAtomic.h>

@interface ViewController ()
{
    NSLock * _lock;
    NSComparator sort;
    UILabel *lab;
    NSMutableString *mutLogStr;
    NSArray *nameArray;
}
//剩余票數(shù)
@property(nonatomic,assign) int leftTicketsCount;
@property(nonatomic,assign) int leftTicketsCount0;
@property(nonatomic,strong)NSMutableArray *threadArr;//存放線程數(shù)組
@property(nonatomic,strong)NSMutableArray *methodsArr;//存放方法名數(shù)組

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor blackColor];
    // Do any additional setup after loading the view, typically from a nib.
    /**
     1. @synchronized 關鍵字加鎖
     2. NSLock 對象鎖
     3. NSCondition 條件鎖1
     4. NSConditionLock 條件鎖2
     5. NSRecursiveLock 遞歸鎖
     6. pthread_mutex 互斥鎖(C語言)
     7. pthread_mutex(recursive) 互斥鎖(C語言)2
     8. dispatch_semaphore 信號量實現(xiàn)加鎖(GCD)
     9. OSSpinLock 自旋鎖P鹱@峡汀!U鸲!k逝椤(已不安全)
     
     **/
    /**
     數(shù)據(jù)對象初始化
     **/
    _threadArr      = [[NSMutableArray alloc]init];
    _methodsArr     = [[NSMutableArray alloc]init];
    _lock           = [[NSLock alloc] init];
    mutLogStr       = [[NSMutableString alloc]init];
    
    /**
     界面UI按鈕初始化
     **/
    nameArray=[NSArray arrayWithObjects:@"關鍵字鎖-@synchronized",@"對象鎖-NSLock",@"條件鎖-1NSCondition",@"條件鎖2-NSConditionLock",@"遞歸鎖-NSRecursiveLock",@"互斥鎖-pthread_mutex",@"互斥鎖2-pthread_mutex(recursive)",@"信號量實現(xiàn)加鎖-dispatch_semaphore",@"自旋鎖-OSSpinLock自旋鎖",@"一千萬次線程鎖空操作性能對比-runLock", nil];

    for (int i=0;i<[nameArray count];i++) {
        UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
        button.tag       = i+1;
        [button setTitle:[nameArray objectAtIndex:i] forState:UIControlStateNormal];
        [button setFrame:CGRectMake(20,30+35*i,Screen_Width-40, 25)];
        [self.view addSubview:button];
        [button addTarget:self action:@selector(buttonClicked:) forControlEvents:UIControlEventTouchUpInside];
        CALayer *layer    = [button layer];
        layer.borderColor = [UIColor purpleColor].CGColor;
        layer.borderWidth = 1;
        
    }

    lab  = [[UILabel alloc]init];
    lab.numberOfLines = 0;
    lab.textColor     = [UIColor whiteColor];
    [lab setFrame:CGRectMake(0,30+(35*[nameArray count]),Screen_Width,Screen_Height-(30+35*[nameArray count]))];
    [self.view addSubview:lab];
    CALayer *layer    = [lab layer];
    layer.borderColor = [UIColor whiteColor].CGColor;
    layer.borderWidth = 3;
    /**
     獲取所有鎖方法
     **/
    unsigned int count;
    Method *methods = class_copyMethodList([self class], &count);
    for (int i = 0; i < count; i++)
    {
        Method method = methods[i];
        SEL selector = method_getName(method);
        NSString *name = NSStringFromSelector(selector);
        
        if ([name hasPrefix:@"sellTickets"]) {
            [_methodsArr addObject:name];
        }
        NSLog(@"方法 名字 ==== %@",name);
        NSLog(@"Test '%@' completed successfuly", [name substringFromIndex:4]);
    }
    /**
     字符串數(shù)組排序
     **/
    NSStringCompareOptions comparisonOptions = NSCaseInsensitiveSearch|NSNumericSearch|
    NSWidthInsensitiveSearch|NSForcedOrderingSearch;
    sort = ^(NSString *obj1,NSString *obj2){
        NSRange range = NSMakeRange(0,obj1.length);
        return [obj1 compare:obj2 options:comparisonOptions range:range];
    };
    NSArray *resultArray = [_methodsArr sortedArrayUsingComparator:sort];
    [_methodsArr setArray:resultArray];
    NSLog(@"字符串數(shù)組排序結果%@",resultArray);
    
    
    self.leftTicketsCount=100;
}

-(void)meathodGet:(SEL)selector
{
    if (_threadArr.count>0) {
        for (int i=0; i<_threadArr.count; i++) {
            NSThread *thread=[_threadArr objectAtIndex:i];
            [thread  cancel];
            thread = nil;
        }
    }
    [_threadArr removeAllObjects];
    for (int i=0; i<10; i++) {
        NSThread *thread=[[NSThread alloc]initWithTarget:self selector:selector object:nil];
        char chStr = i + 'A';
        thread.name=[NSString stringWithFormat:@"售票員%c",chStr];
        [_threadArr addObject:thread];
        [thread start];
    }
}

/**
 1. @synchronized 關鍵字加鎖
 @synchronized指令實現(xiàn)鎖的優(yōu)點就是我們不需要在代碼中顯式的創(chuàng)建鎖對象,便可以實現(xiàn)鎖的機制苇瓣,但作為一種預防措施尉间,
 @synchronized塊會隱式的添加一個異常處理例程來保護代碼,該處理例程會在異常拋出的時候自動的釋放互斥鎖。所以如果不想讓隱
 式的異常處理例程帶來額外的開銷哲嘲,你可以考慮使用鎖對象贪薪。
 **/
-(void)sellTickets
 {
        while (1) {
         @synchronized(self){//只能加一把鎖 ['s??kr?na?zd]
             //1.先檢查票數(shù)
             int count=self.leftTicketsCount;
             if (count>0) {
                    //休眠一段時間
                    sleep(1);
                    //2.票數(shù)-1
                    self.leftTicketsCount= count-1;
                    //獲取當前線程
                    NSThread *current=[NSThread currentThread];
                 
                 [self logGetStr:[NSString stringWithFormat:@"%@--賣了一張票,還剩余%d張票",current.name,self.leftTicketsCount]];
                 DEBUGLog(@"%@--賣了一張票眠副,還剩余%d張票",current.name,self.leftTicketsCount);
                 }else{
                     //退出線程
                     [NSThread exit];
                 }
             }
        }
}

/**
 2. NSLock 對象鎖
 NSLock是我們經(jīng)常所使用的画切,除lock和unlock方法外,NSLock還提供了tryLock,lockBeforeDate:兩個方法
 tryLock:會嘗試加鎖囱怕,如果鎖不可用(已經(jīng)被鎖住)霍弹,剛并不會阻塞線程,并返回NO娃弓。
 lockBeforeDate:方法會在所指定Date之前嘗試加鎖典格,如果在指定時間之前都不能加鎖,則返回NO台丛。
 **/
- (void)sellTickets2
{
    while (1) {
        [_lock lock];
        int count=self.leftTicketsCount;
        if (count>0) {
            //休眠一段時間
            sleep(1);
            //2.票數(shù)-1
            self.leftTicketsCount= count-1;
            //獲取當前線程
            NSThread *current=[NSThread currentThread];
            [self logGetStr:[NSString stringWithFormat:@"%@--賣了一張票耍缴,還剩余%d張票",current.name,self.leftTicketsCount]];
            NSLog(@"%@--賣了一張票,還剩余%d張票",current.name,self.leftTicketsCount);
        }else{
            //退出線程
            [NSThread exit];
        }
        [_lock unlock];
    }
}

/**
 3 NSCondition 條件鎖1
 一種最基本的條件鎖挽霉。手動控制線程wait和signal防嗡。當我們在使用多線程的時候,普通的鎖只是直接的鎖與不鎖侠坎,而我們在處理資源
 共享的時候很多情況下下需要滿足一定條件的情況下才能打開這把鎖
 
 [condition lock];多用于多線程同時訪問本鸣、修改同一個數(shù)據(jù)源,保證在同一時間內(nèi)數(shù)據(jù)源只被訪問硅蹦、修改一次,其他線程
 要在lock外等待闷煤,只到unlock才可訪問

 [condition unlock];與lock 同時使用
 
 [condition wait];讓當前線程處于等待狀態(tài)
 
 [condition signal];CPU發(fā)信號告訴線程不用在等待童芹,可以繼續(xù)執(zhí)行
 
 使用場1:景圖片消息:
 當接受到圖片消息的時候,需要異步下載鲤拿,等到圖片下載完成之后假褪,同步數(shù)據(jù)庫,方可通知前端更新UI近顷。此時就需要使用
 NSCondition 的wait
 
 使用場2:數(shù)據(jù)加載上傳:
 位置變化收集經(jīng)緯度數(shù)據(jù)生音,當達到500個點時上傳服務器成功后清空(當然這里還有中間層數(shù)據(jù)中轉)。此時就需要使用
 NSCondition 的wait
 
 窒升,方可通知前端更新UI缀遍。此時就需要使用
 NSCondition 的wait
 **/

- (void)sellTickets3
{
    NSCondition *condition   = [[NSCondition alloc] init];
    NSMutableArray *products = [NSMutableArray array];
    
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        while (1) {
            [condition lock];
            if ([products count] < self.leftTicketsCount) {
                NSLog(@"等待經(jīng)緯度數(shù)據(jù)收集...");
                [condition wait];
            }else{
                NSLog(@"經(jīng)緯度數(shù)據(jù)滿載處理");
                [products removeAllObjects];
            }
            [condition unlock];
        }
        
    });
    
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        while (1) {
            [condition lock];
            [products addObject:@"+1"];
            NSLog(@"經(jīng)緯度數(shù)據(jù),點個數(shù):%zi",products.count);
            [condition signal];
            [condition unlock];
            sleep(1);
        }
        
    });

}

/**
 4 NSConditionLock 條件鎖 2
 
 **/

- (void)sellTickets4
{
    NSMutableArray *products = [NSMutableArray array];
    NSConditionLock *lock    = [[NSConditionLock alloc]init];
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        while (1) {
            [lock lockWhenCondition:0];
            for (int i=0; i<self.leftTicketsCount; i++) {
                sleep(1);
                [products addObject:@"+1"];
                NSLog(@"正在收集經(jīng)緯度數(shù)據(jù)...,點個數(shù):%zi",products.count);
                [self logGetStr:[NSString stringWithFormat:@"正在收集經(jīng)緯度數(shù)據(jù)...,點個數(shù):%zi",products.count]];
            }
            [lock unlockWithCondition:[products count]];
            sleep(1);
        }
        
    });
    
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        while (1) {
            NSLog(@"等待經(jīng)緯度數(shù)據(jù)收集...");
            [self logGetStr:[NSString stringWithFormat:@"等待經(jīng)緯度數(shù)據(jù)收集..."]];
            [lock lockWhenCondition:self.leftTicketsCount];
            [products removeAllObjects];
            NSLog(@"經(jīng)緯度數(shù)據(jù)收集滿載處理");
            [self logGetStr:[NSString stringWithFormat:@"經(jīng)緯度數(shù)據(jù)收集滿載處理"]];
            [lock unlockWithCondition:[products count]];
        }
        
    });
    
}

/**
 5. NSRecursiveLock 遞歸鎖
 NSRecursiveLock 遞歸鎖 主要用在循環(huán)或遞歸操作中,它可以被同一線程多次請求,而不會引起死鎖饱须。
 <NSLock>這是一個典型的死鎖情況域醇。在我們的線程中,recursionMethod是遞歸調(diào)用。所以每次進入這個block時譬挚,都會去加一次
 鎖锅铅,從第二次開始,由于鎖已經(jīng)被使用并且沒有解鎖减宣,所以它要等待鎖被解除盐须,這樣就導致了死鎖,線程被阻塞住了漆腌。
 bugLog輸出如下信息:
 *** -[NSLock lock]: deadlock (<NSLock: 0x1740daf60> '(null)')
 *** Break on _NSLockError() to debug.
 <NSRecursiveLock>換成遞歸鎖一切正常了
 **/
- (void)sellTickets5
{
//    NSLock *recursiveLock = [[NSLock alloc] init];
    NSRecursiveLock *recursiveLock = [[NSRecursiveLock alloc] init];
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        
        static void (^recursionMethod)(int);
        recursionMethod = ^(int value) {
            
            [recursiveLock lock];
            if (value > 0) {
                
                NSLog(@"value = %d", value);
                [self logGetStr:[NSString stringWithFormat:
                                 @"value = %d", value]];
                sleep(1);
                recursionMethod(value - 1);
            }
            [recursiveLock unlock];
        };
        recursionMethod(5);
    });
}
/**
 6. pthread_mutex 互斥鎖(C語言)
 c語言定義下多線程加鎖方式贼邓。
 
 1:pthread_mutex_init(pthread_mutex_t mutex,const pthread_mutexattr_t attr);
    初始化鎖變量mutex。attr為鎖屬性屉凯,NULL值為默認屬性立帖。
 2:pthread_mutex_lock(pthread_mutex_t mutex);加鎖
 3:pthread_mutex_tylock(*pthread_mutex_t *mutex);加鎖,當鎖已經(jīng)在使用的時候悠砚,返回為
    EBUSY晓勇,而不是掛起等待。
 4:pthread_mutex_unlock(pthread_mutex_t *mutex);釋放鎖
 5:pthread_mutex_destroy(pthread_mutex_t* mutex);使用完后釋放
 **/
- (void)sellTickets6
{
    __block pthread_mutex_t theLock;
    pthread_mutex_init(&theLock, NULL);
    
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        pthread_mutex_lock(&theLock);
        NSLog(@"電腦開機...");
        sleep(1);
        NSLog(@"輸入密碼...");
        pthread_mutex_unlock(&theLock);
        
    });
    
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        sleep(2);
        pthread_mutex_lock(&theLock);
        NSLog(@"進入桌面");
        pthread_mutex_unlock(&theLock);
        
    });
}

/**
 7. pthread_mutex(recursive) 互斥鎖(C語言)2
 **/
-(void)sellTickets7
{
    __block pthread_mutex_t theLock;
//    pthread_mutex_init(&theLock, NULL);
    
    pthread_mutex_t Mutex;
    pthread_mutexattr_t Attr;
    
    pthread_mutexattr_init(&Attr);
    pthread_mutexattr_settype(&Attr, PTHREAD_MUTEX_RECURSIVE);
    pthread_mutex_init(&Mutex, &Attr);
    pthread_mutexattr_destroy(&Attr);
    
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        
        static void (^recursionMethod)(int);
        
        recursionMethod = ^(int value) {
            
            pthread_mutex_lock(&theLock);
            if (value > 0) {
                
                NSLog(@"value = %d", value);
                sleep(1);
                recursionMethod(value - 1);
            }
            pthread_mutex_unlock(&theLock);
        };
        
        recursionMethod(self.leftTicketsCount);
    });

}

/**
 8. dispatch_semaphore 信號量實現(xiàn)加鎖(GCD)
 dispatch_semaphore是GCD用來同步的一種方式灌旧,與他相關的共有三個函數(shù)绑咱,分別是
 dispatch_semaphore_create,
 dispatch_semaphore_signal枢泰,dispatch_semaphore_wait描融。
 **/

-(void)sellTickets8
{
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        for (int i = 0; i < self.leftTicketsCount0; i++)
        {
            dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
                dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
                int count=self.leftTicketsCount;
                if (count>0) {
                    //休眠一段時間
                    sleep(1);
                    //2.票數(shù)-1
                    self.leftTicketsCount= count-1;
                    NSThread *current=[NSThread currentThread];
                    //獲取當前線程
                    NSLog(@"%@--賣了一張票,還剩余%d張票",current,self.leftTicketsCount);
                }
                dispatch_semaphore_signal(semaphore);
            });
            
        }
    });
        NSLog(@"我是主線程");
}
/**
 9. OSSpinLock 自旋鎖:饴臁A恕!C住D甓!(已不安全不推薦使用,謹慎使用)
 OSSpinLock 自旋鎖,性能最高的鎖.因為其是一直等待狀態(tài)玻募,因此對CUP要求很高只损,消耗大量CPU資源
 不適宜長時使用,耗電七咧,好資源發(fā)熱高
 OSSpinLock已經(jīng)不再安全@"http://blog.ibireme.com/2016/01/16/spinlock_is_unsafe_in_ios/"
  **/

- (void)sellTickets9
{
    __block OSSpinLock theLock = OS_SPINLOCK_INIT;
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        OSSpinLockLock(&theLock);
        NSLog(@"電腦開機...");
        sleep(2);
        NSLog(@"輸入密碼...");
        OSSpinLockUnlock(&theLock);
        
    });
    
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        OSSpinLockLock(&theLock);
        sleep(1);
        NSLog(@"進入桌面");
        OSSpinLockUnlock(&theLock);
        
    });
    
}

-(void)buttonClicked:(UIButton*)btAction
{
    [mutLogStr setString:[NSString stringWithFormat:@"** %@\n",[nameArray objectAtIndex:btAction.tag-1]]];
    self.leftTicketsCount  = 5;
    self.leftTicketsCount0 = 5;
    
    if (btAction.tag<=2) {//1. @synchronized 關鍵字加鎖
        
        SEL selector = NSSelectorFromString([_methodsArr objectAtIndex:btAction.tag-1]);
        [self meathodGet:selector];
        
    }else{
        SEL selector = NSSelectorFromString([_methodsArr objectAtIndex:btAction.tag-1]);
        [self performSelector:selector];
    }
    
}

/**
 一千萬次線程鎖空操作性能對比-sellTickets10
 **/
- (void)sellTickets10{

    NSMutableDictionary *sortDic   = [[NSMutableDictionary alloc]init];
    NSString *timestr;
    CFTimeInterval timeBefore;
    CFTimeInterval timeCurrent;
    NSUInteger i;
    NSUInteger count = 1000*10000;//執(zhí)行一千萬次
    
    //OSSpinLockLock自旋鎖  T颈埂!0啊1妗!(已不安全)CFAbsoluteTimeGetCurrent
    OSSpinLock spinlock = OS_SPINLOCK_INIT;
    timeBefore = CACurrentMediaTime();
    for(i=0; i<count; i++){
        OSSpinLockLock(&spinlock);
        OSSpinLockUnlock(&spinlock);
    }
    timeCurrent = CACurrentMediaTime();
    timestr = [NSString stringWithFormat:@"%f",timeCurrent-timeBefore];
    [sortDic setValue:@"OSSpinLock" forKey:timestr];
    
    //@synchronized關鍵字加鎖
    id obj = [[NSObject alloc]init];;
    timeBefore = CACurrentMediaTime();
    for(i=0; i<count; i++){
        @synchronized(obj){
        }
    }
    timeCurrent = CACurrentMediaTime();
    timestr = [NSString stringWithFormat:@"%f",timeCurrent-timeBefore];
    [sortDic setValue:@"@synchronized" forKey:timestr];
    
    //NSLock對象鎖
    NSLock *lock = [[NSLock alloc]init];
    timeBefore = CACurrentMediaTime();
    for(i=0; i<count; i++){
        [lock lock];
        [lock unlock];
    }
    timeCurrent = CACurrentMediaTime();
    timestr = [NSString stringWithFormat:@"%f",timeCurrent-timeBefore];
    [sortDic setValue:@"NSLock" forKey:timestr];
    
    //NSCondition條件鎖1
    NSCondition *condition = [[NSCondition alloc]init];
    timeBefore = CACurrentMediaTime();
    for(i=0; i<count; i++){
        [condition lock];
        [condition unlock];
    }
    timeCurrent = CACurrentMediaTime();
    timestr = [NSString stringWithFormat:@"%f",timeCurrent-timeBefore];
    [sortDic setValue:@"NSCondition" forKey:timestr];

    //NSConditionLock條件鎖2
    NSConditionLock *conditionLock = [[NSConditionLock alloc]init];
    timeBefore = CACurrentMediaTime();
    for(i=0; i<count; i++){
        [conditionLock lock];
        [conditionLock unlock];
    }
    timeCurrent = CACurrentMediaTime();
    timestr = [NSString stringWithFormat:@"%f",timeCurrent-timeBefore];
    [sortDic setValue:@"NSConditionLock" forKey:timestr];

    //NSRecursiveLock遞歸鎖
    NSRecursiveLock *recursiveLock = [[NSRecursiveLock alloc]init];
    timeBefore = CACurrentMediaTime();
    for(i=0; i<count; i++){
        [recursiveLock lock];
        [recursiveLock unlock];
    }
    timeCurrent = CACurrentMediaTime();
    timestr = [NSString stringWithFormat:@"%f",timeCurrent-timeBefore];
    [sortDic setValue:@"NSRecursiveLock" forKey:timestr];
    
    //pthread_mutex互斥鎖1(C語言)
    pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
    timeBefore = CACurrentMediaTime();
    for(i=0; i<count; i++){
        pthread_mutex_lock(&mutex);
        pthread_mutex_unlock(&mutex);
    }
    timeCurrent = CACurrentMediaTime();
    timestr = [NSString stringWithFormat:@"%f",timeCurrent-timeBefore];
    [sortDic setValue:@"pthread_mutexpthread_mutex" forKey:timestr];
    
    //pthread_mutex(recursive)互斥鎖2(C語言)
    
    pthread_mutex_t lockrecursive;
    pthread_mutexattr_t attr;
    pthread_mutexattr_init(&attr);
    pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
    pthread_mutex_init(&lockrecursive, &attr);
    pthread_mutexattr_destroy(&attr);
    timeBefore = CACurrentMediaTime();
    for (int i = 0; i < count; i++) {
        pthread_mutex_lock(&lockrecursive);
        pthread_mutex_unlock(&lockrecursive);
    }
    timeCurrent = CACurrentMediaTime();
    timestr = [NSString stringWithFormat:@"%f",timeCurrent-timeBefore];
    [sortDic setValue:@"pthread_mutex(recursive)" forKey:timestr];
    
    
    
    //dispatch_semaphore信號量實現(xiàn)加鎖(GCD)
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
    timeBefore = CACurrentMediaTime();
    for(i=0; i<count; i++){
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        dispatch_semaphore_signal(semaphore);
    }
    timeCurrent = CACurrentMediaTime();
    timestr = [NSString stringWithFormat:@"%f",timeCurrent-timeBefore];
    [sortDic setValue:@"dispatch_semaphore" forKey:timestr];

    DEBUGLog(@"sortDic===%@",sortDic);
    NSArray *resultArray = [[sortDic allKeys] sortedArrayUsingComparator:sort];
    NSMutableAttributedString *contentForgeta  = [[NSMutableAttributedString alloc]initWithString:mutLogStr];
    for (int i=0;i<[resultArray count];i++) {
     
     NSMutableAttributedString *contentForget = [[NSMutableAttributedString alloc]initWithString:[NSString stringWithFormat:@"** %i.%@----%@\n",i+1,[sortDic objectForKey:[resultArray objectAtIndex:i]],[resultArray objectAtIndex:i]]];
     NSRange contentRange = {contentForget.length-9,8};
     [contentForget addAttribute:NSForegroundColorAttributeName
                           value:[UIColor redColor]
                           range:contentRange];
     [contentForget addAttribute:NSUnderlineStyleAttributeName
                           value:[NSNumber numberWithInteger:NSUnderlineStyleSingle]
                           range:contentRange];
    [contentForgeta appendAttributedString:contentForget];
     
    }
    lab.attributedText = contentForgeta;
    DEBUGLog(@"%@",lab.text);

}

-(void)logGetStr:(NSString*)logStr
{
    [mutLogStr appendString:[NSString stringWithFormat:@"** %@\n",logStr]];
    dispatch_async(dispatch_get_main_queue(), ^{
        lab.text = mutLogStr;
    });
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end

GitHub地址:https://github.com/Yjunjie/MultithreadingAndLock/tree/master

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末裹粤,一起剝皮案震驚了整個濱河市终蒂,隨后出現(xiàn)的幾起案子蜂林,更是在濱河造成了極大的恐慌,老刑警劉巖拇泣,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件噪叙,死亡現(xiàn)場離奇詭異,居然都是意外死亡霉翔,警方通過查閱死者的電腦和手機睁蕾,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來债朵,“玉大人子眶,你說我怎么就攤上這事⌒蚵” “怎么了臭杰?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長谚中。 經(jīng)常有香客問我渴杆,道長,這世上最難降的妖魔是什么宪塔? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任磁奖,我火速辦了婚禮,結果婚禮上某筐,老公的妹妹穿的比我還像新娘比搭。我一直安慰自己,他們只是感情好南誊,可當我...
    茶點故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布身诺。 她就那樣靜靜地躺著,像睡著了一般抄囚。 火紅的嫁衣襯著肌膚如雪戚长。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天怠苔,我揣著相機與錄音,去河邊找鬼仪糖。 笑死柑司,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的锅劝。 我是一名探鬼主播攒驰,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼故爵!你這毒婦竟也來了玻粪?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎劲室,沒想到半個月后伦仍,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡很洋,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年充蓝,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片喉磁。...
    茶點故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡谓苟,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出协怒,到底是詐尸還是另有隱情涝焙,我是刑警寧澤,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布孕暇,位于F島的核電站仑撞,受9級特大地震影響,放射性物質發(fā)生泄漏芭商。R本人自食惡果不足惜派草,卻給世界環(huán)境...
    茶點故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望铛楣。 院中可真熱鬧近迁,春花似錦、人聲如沸簸州。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽岸浑。三九已至搏存,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間矢洲,已是汗流浹背璧眠。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留读虏,地道東北人责静。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像盖桥,于是被迫代替她去往敵國和親灾螃。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,786評論 2 345

推薦閱讀更多精彩內(nèi)容

  • iOS線程安全的鎖與性能對比 一揩徊、鎖的基本使用方法 1.1腰鬼、@synchronized 這是我們最熟悉的枷鎖方式嵌赠,...
    Jacky_Yang閱讀 2,207評論 0 17
  • demo下載 建議一邊看文章,一邊看代碼熄赡。 聲明:關于性能的分析是基于我的測試代碼來的姜挺,我也看到和網(wǎng)上很多測試結果...
    炸街程序猿閱讀 781評論 0 2
  • 鎖是一種同步機制,用于多線程環(huán)境中對資源訪問的限制iOS中常見鎖的性能對比圖(摘自:ibireme): iOS鎖的...
    LiLS閱讀 1,507評論 0 6
  • 一本谜、前言 前段時間看了幾個開源項目初家,發(fā)現(xiàn)他們保持線程同步的方式各不相同,有@synchronized乌助、NSLock...
    景銘巴巴閱讀 28,670評論 17 231
  • 選擇晚上做仰臥起坐不是個好主意溜在。 每次完成100個玷过,都惡心想吐聪舒,需要至少20分鐘恢復常態(tài)。 主要原因蹂楣, 1.屋里不...
    完顏三十閱讀 209評論 5 0