iOS 线程管理的学习记录
-
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
- (void)method1{NSLog(@%@,NSStringFromSelector(_cmd));}- (void)method2{NSLog(@%@,NSStringFromSelector(_cmd));}/*线程1锁住之后,线程2会一直等待走到线程1将锁置为unlock后,才会执行method2方法。NSLock是Cocoa提供给我们最基本的锁对象,这也是我们经常所使用的,除lock和unlock方法外,NSLock还提供了tryLock和lockBeforeDate:两个方法,前一个方法会尝试加锁,如果锁不可用(已经被锁住),刚并不会阻塞线程,并返回NO。lockBeforeDate:方法会在所指定Date之前尝试加锁,如果在指定时间之前都不能加锁,则返回NO。*/- (IBAction)NSLock:(id)sender {NSLock *lock = [[NSLock alloc] init];//线程1dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{[lock lock];[self method1];sleep(10);[lock unlock];});//线程2dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{sleep(1);//以保证让线程2的代码后执行[lock lock];[self method2];[lock unlock];});}/*@synchronized指令使用的obj为该锁的唯一标识,只有当标识相同时,才为满足互斥,如果线程2中的@synchronized(obj)改为@synchronized(other),刚线程2就不会被阻塞,@synchronized指令实现锁的优点就是我们不需要在代码中显式的创建锁对象,便可以实现锁的机制,但作为一种预防措施,@synchronized块会隐式的添加一个异常处理例程来保护代码,该处理例程会在异常抛出的时候自动的释放互斥锁。所以如果不想让隐式的异常处理例程带来额外的开销,你可以考虑使用锁对象。*/- (IBAction)synchronized:(id)sender {//线程1dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{@synchronized(self){[self method1];sleep(5);}});//线程2dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{sleep(1);@synchronized(self){[self method2];}});}- (IBAction)pthread_mutex_t:(id)sender {__block pthread_mutex_t mutex;pthread_mutex_init(&mutex, NULL);//线程1dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{pthread_mutex_lock(&mutex);[self method1];sleep(5);pthread_mutex_unlock(&mutex);});//线程2dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{sleep(1);pthread_mutex_lock(&mutex);[self method2];pthread_mutex_unlock(&mutex);});}- (IBAction)GCD:(id)sender {dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);//线程1dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);[self method1];sleep(10);dispatch_semaphore_signal(semaphore);});//线程2dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{sleep(1);dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);[self method2];dispatch_semaphore_signal(semaphore);});}/* NSRecursiveLock递归锁在线程1中的递归block中,锁会被多次的lock,所以自己也被阻塞了,由于以上的代码非常的简短,所以很容易能识别死锁,但在较为复杂的代码中,就不那么容易发现了,那么如何在递归或循环中正确的使用锁呢?此处的theLock如果换用NSRecursiveLock对象,问题便得到解决了,NSRecursiveLock类定义的锁可以在同一线程多次lock,而不会造成死锁。递归锁会跟踪它被多少次lock。每次成功的lock都必须平衡调用unlock操作。只有所有的锁住和解锁操作都平衡的时候,锁才真正被释放给其他线程获得。*/- (IBAction)NSRecursiveLock:(id)sender {NSRecursiveLock *theLock = [[NSRecursiveLock alloc] init];// TestObj *obj = [[TestObj alloc] init];//线程1dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{staticvoid(^TestMethod)(int);TestMethod = ^(intvalue){[theLock lock];if(value >0){[self method1];sleep(5);TestMethod(value-1);}[theLock unlock];};TestMethod(5);});//线程2dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{sleep(1);[theLock lock];[self method2];[theLock unlock];});}/* NSConditionLock条件锁在线程1中的加锁使用了lock,所以是不需要条件的,所以顺利的就锁住了,但在unlock的使用了一个整型的条件,它可以开启其它线程中正在等待这把钥匙的临界地,而线程2则需要一把被标识为2的钥匙,所以当线程1循环到最后一次的时候,才最终打开了线程2中的阻塞。但即便如此,NSConditionLock也跟其它的锁一样,是需要lock与unlock对应的,只是lock,lockWhenCondition:与unlock,unlockWithCondition:是可以随意组合的,当然这是与你的需求相关的。*/- (IBAction)NSConditionLock:(id)sender {//主线程中NSConditionLock *theLock = [[NSConditionLock alloc] init];//线程1dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{for(inti=0;i<=2;i++){[theLock lock];NSLog(@thread1:%d,i);sleep(2);[theLock unlockWithCondition:i];}});//线程2dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{[theLock lockWhenCondition:2];NSLog(@thread2);[theLock unlock];});}今天发现了非常好的线程管理的文章,特此贴出来学习一下,最后还有一块并没有试验,再次也贴出来,大家可以参考一下
NSDistributedLock分布式锁
以上所有的锁都是在解决多线程之间的冲突,但如果遇上多个进程或多个程序之间需要构建互斥的情景该怎么办呢?这个时候我们就需要使用到NSDistributedLock了,从它的类名就知道这是一个分布式的Lock,NSDistributedLock的实现是通过文件系统的,所以使用它才可以有效的实现不同进程之间的互斥,但NSDistributedLock并非继承于NSLock,它没有lock方法,它只实现了tryLock,unlock,breakLock,所以如果需要lock的话,你就必须自己实现一个tryLock的轮询,下面通过代码简单的演示一下吧
12345678dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{lock = [[NSDistributedLock alloc] initWithPath:@/Users/mac/Desktop/earning__];[lock breakLock];[lock tryLock];sleep(10);[lock unlock];NSLog(@appA: OK);});
12345678910dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{lock = [[NSDistributedLock alloc] initWithPath:@/Users/mac/Desktop/earning__];while(![lock tryLock]) {NSLog(@appB: waiting);sleep(1);}[lock unlock];NSLog(@appB: OK);});
先运行程序A,然后立即运行程序B,根据打印你可以清楚的发现,当程序A刚运行的时候,程序B一直处于等待中,当大概10秒过后,程序B便打印出了appB:OK的输出,以上便实现了两上不同程序之间的互斥。/Users/mac/Desktop/earning__是一个文件或文件夹的地址,如果该文件或文件夹不存在,那么在tryLock返回YES时,会自动创建该文件/文件夹。在结束的时候该文件/文件夹会被清除,所以在选择的该路径的时候,应该选择一个不存在的路径,以防止误删了文件。个人觉得除了这些以外,之前还在工作当中用到过一个关于NSTimer的线程管理,那就是timer的暂停和继续,在此也贴出代码
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051//为NSTimer添加一个分类#importTFTimer.h#import<foundation foundation.h="">@interfaceNSTimer (TFAddition)-(void)pauseTimer;-(void)resumeTimer;@end#importTFTimer.h@implementationNSTimer (TFAddition)-(void)pauseTimer{if(![self isValid]) {return;}[self setFireDate:[NSDate distantFuture]];//如果给我一个期限,我希望是4001-01-01 00:00:00 +0000}-(void)resumeTimer{if(![self isValid]) {return;}//[self setFireDate:[NSDate dateWithTimeIntervalSinceNow:0]];[self setFireDate:[NSDate date]];}@end</foundation>

浙公网安备 33010602011771号