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 信号量实现加锁(GCD)
9. OSSpinLock 自旋锁!!!!!(已不安全)无法保证和控制优先级不同的线程的调度,除非所有优先级都是一样的,而除非带出来的话往往木有意义

一.不废话直接贴代码

GitHub地址:https://github.com/Yjunjie/MultithreadingAndLock/tree/master
基本都是根据实际情况设立的情境,买票,网络数据加载处理,网络数据上传处理等等。部分操作如图:
1.多售票员卖票情境
http://upload-images.jianshu.io/upload_images/6285199-f054d3f3b9473816.gif?imageMogr2/auto-orient/strip

2017-06-15 16_25_31.gif

2.用户路线缓存,经纬度数据点上传
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 自旋锁已经不再安全,不推荐或者慎重使用
OSSpinLock 自旋锁
dispatch_semaphore 信号量实现加锁(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;
}
//剩余票数
@property(nonatomic,assign) int leftTicketsCount;
@property(nonatomic,assign) int leftTicketsCount0;
@property(nonatomic,strong)NSMutableArray *threadArr;//存放线程数组
@property(nonatomic,strong)NSMutableArray *methodsArr;//存放方法名数组

@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 信号量实现加锁(GCD)
     9. OSSpinLock 自旋锁!!!!!(已不安全)
     
     **/
    /**
     数据对象初始化
     **/
    _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)",@"信号量实现加锁-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]);
    }
    /**
     字符串数组排序
     **/
    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(@"字符串数组排序结果%@",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指令实现锁的优点就是我们不需要在代码中显式的创建锁对象,便可以实现锁的机制,但作为一种预防措施,
 @synchronized块会隐式的添加一个异常处理例程来保护代码,该处理例程会在异常抛出的时候自动的释放互斥锁。所以如果不想让隐
 式的异常处理例程带来额外的开销,你可以考虑使用锁对象。
 **/
-(void)sellTickets
 {
        while (1) {
         @synchronized(self){//只能加一把锁 ['sɪŋkrənaɪzd]
             //1.先检查票数
             int count=self.leftTicketsCount;
             if (count>0) {
                    //休眠一段时间
                    sleep(1);
                    //2.票数-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是我们经常所使用的,除lock和unlock方法外,NSLock还提供了tryLock,lockBeforeDate:两个方法
 tryLock:会尝试加锁,如果锁不可用(已经被锁住),刚并不会阻塞线程,并返回NO。
 lockBeforeDate:方法会在所指定Date之前尝试加锁,如果在指定时间之前都不能加锁,则返回NO。
 **/
- (void)sellTickets2
{
    while (1) {
        [_lock lock];
        int count=self.leftTicketsCount;
        if (count>0) {
            //休眠一段时间
            sleep(1);
            //2.票数-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];多用于多线程同时访问、修改同一个数据源,保证在同一时间内数据源只被访问、修改一次,其他线程
 要在lock外等待,只到unlock才可访问

 [condition unlock];与lock 同时使用
 
 [condition wait];让当前线程处于等待状态
 
 [condition signal];CPU发信号告诉线程不用在等待,可以继续执行
 
 使用场1:景图片消息:
 当接受到图片消息的时候,需要异步下载,等到图片下载完成之后,同步数据库,方可通知前端更新UI。此时就需要使用
 NSCondition 的wait
 
 使用场2:数据加载上传:
 位置变化收集经纬度数据,当达到500个点时上传服务器成功后清空(当然这里还有中间层数据中转)。此时就需要使用
 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(@"等待经纬度数据收集...");
                [condition wait];
            }else{
                NSLog(@"经纬度数据满载处理");
                [products removeAllObjects];
            }
            [condition unlock];
        }
        
    });
    
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        while (1) {
            [condition lock];
            [products addObject:@"+1"];
            NSLog(@"经纬度数据,点个数:%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(@"正在收集经纬度数据...,点个数:%zi",products.count);
                [self logGetStr:[NSString stringWithFormat:@"正在收集经纬度数据...,点个数:%zi",products.count]];
            }
            [lock unlockWithCondition:[products count]];
            sleep(1);
        }
        
    });
    
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        while (1) {
            NSLog(@"等待经纬度数据收集...");
            [self logGetStr:[NSString stringWithFormat:@"等待经纬度数据收集..."]];
            [lock lockWhenCondition:self.leftTicketsCount];
            [products removeAllObjects];
            NSLog(@"经纬度数据收集满载处理");
            [self logGetStr:[NSString stringWithFormat:@"经纬度数据收集满载处理"]];
            [lock unlockWithCondition:[products count]];
        }
        
    });
    
}

/**
 5. NSRecursiveLock 递归锁
 NSRecursiveLock 递归锁 主要用在循环或递归操作中,它可以被同一线程多次请求,而不会引起死锁。
 <NSLock>这是一个典型的死锁情况。在我们的线程中,recursionMethod是递归调用。所以每次进入这个block时,都会去加一次
 锁,从第二次开始,由于锁已经被使用并且没有解锁,所以它要等待锁被解除,这样就导致了死锁,线程被阻塞住了。
 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);加锁,当锁已经在使用的时候,返回为
    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 信号量实现加锁(GCD)
 dispatch_semaphore是GCD用来同步的一种方式,与他相关的共有三个函数,分别是
 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.票数-1
                    self.leftTicketsCount= count-1;
                    NSThread *current=[NSThread currentThread];
                    //获取当前线程
                    NSLog(@"%@--卖了一张票,还剩余%d张票",current,self.leftTicketsCount);
                }
                dispatch_semaphore_signal(semaphore);
            });
            
        }
    });
        NSLog(@"我是主线程");
}
/**
 9. OSSpinLock 自旋锁!!!!!(已不安全不推荐使用,谨慎使用)
 OSSpinLock 自旋锁,性能最高的锁.因为其是一直等待状态,因此对CUP要求很高,消耗大量CPU资源
 不适宜长时使用,耗电,好资源发热高
 OSSpinLock已经不再安全@"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;//执行一千万次
    
    //OSSpinLockLock自旋锁  !!!!!(已不安全)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信号量实现加锁(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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343

推荐阅读更多精彩内容