Object-C 多线程中锁的使用
//线程1
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
@synchronized(_myLockObj){
[obj1 method1];
sleep(30);
}
@synchronized(obj1){
}
});
//线程2
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
sleep(1);
@synchronized(_myLockObj){
[obj1 method2];
}
});
}
@interface TestObj : NSObject
- (void)method1;
- (void)method2;
@end
#import "TestObj.h"
@implementation TestObj
- (void)method1{
NSLog(@"%@",NSStringFromSelector(_cmd));
NSLog(@"Current thread = %@", [NSThread currentThread]);
NSLog(@"Main thread = %@", [NSThread mainThread]);
}
- (void)method2{
NSLog(@"%@",NSStringFromSelector(_cmd));
NSLog(@"Current thread = %@", [NSThread currentThread]);
NSLog(@"Main thread = %@", [NSThread mainThread]);
}
@end
TestObj *obj = [[TestObj alloc] init];
NSLock *lock = [[NSLock alloc] init];
4.多线程状态下,锁操作
//线程1
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[lock lock];
[obj method1];
sleep(30);
[lock unlock];
});
//线程2
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
sleep(5);//以保证让线程2的代码后执行
[lock lock];
[obj method2];
[lock unlock];
});
使用时,基本方法就是:
[lock lock];
[obj yourMethod];
[lock unlock];
我们称[obj yourMethod]为“关键部分”。
NSLock的执行原理:
某个线程A调用lock方法。这样,NSLock将被上锁。可以执行“关键部分”,完成后,调用unlock方法。
如果,在线程A 调用unlock方法之前,另一个线程B调用了同一锁对象的lock方法。那么,线程B只有等待。直到线程A调用了unlock。
最后,还是看看API中对NSLock的一些说明
@protocol NSLocking
lock 方法
- (void)lock
获得锁
unlock 方法
- (void)unlock
释放锁
@interface NSLock
lockBeforeDate: 方法
- (BOOL)lockBeforeDate:(NSDate *)limit
在指定的时间以前得到锁。YES:在指定时间之前获得了锁;NO:在指定时间之前没有获得锁。
该线程将被阻塞,直到获得了锁,或者指定时间过期。
tryLock 方法
- (BOOL)tryLock
视图得到一个锁。YES:成功得到锁;NO:没有得到锁。
setName: 方法
- (void)setName:(NSString *)newName
为锁指定一个Name
name 方法
- (NSString *)name
返回锁指定的Name
TestObj *obj = [[TestObj alloc] init];
dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
//线程1
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
[obj method1];
sleep(10);
dispatch_semaphore_signal(semaphore);
});
//线程2
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
sleep(1);
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
[obj method2];
dispatch_semaphore_signal(semaphore);
});
Grand Central Dispatch,或者简称 GCD,是一个与 Block Object 产生工作的低级的 C API。GCD 真正的用途是将任务分配到多个核心又不让程序员担心哪个内核执行哪个任务。 在 Max OS X 上,多内核设备,包括笔记本,用户已经使用了相当长的时间。通过多核设备 比如 iPad2 的介绍,程序员能为 iOS 写出神奇的多核多线程 APP。
GCD 的核心是分派队列。不论在 iOS 还是 Max OS X 分派队列,正如我们快看到的是 由位于主操作系统的 GCD 来管理的线程池。你不会直接与线程有工作关系。你只在分派队 列上工作,将任务分派到这个队列上并要求队列来调用你的任务。GCD 为运行任务提供了 几个选择:同步执行、异步执行和延迟执行等。
// 主线程队列,由系统自动创建并且与应用撑血的主线程相关联。
dispatch_queue_t mainQueue = dispatch_get_main_queue();
// 要在主线程队列中,执行的Block
dispatch_async(mainQueue, ^(void) {
[[[UIAlertView alloc] initWithTitle:@"GCD"
message:@"GCD is amazing!"
delegate:nil cancelButtonTitle:@"OK"
otherButtonTitles:nil, nil] show];
});
void dispatch_async(dispatch_queue_t queue,dispatch_block_t block);
dispatch_async_f 方法
void dispatch_async_f(dispatch_queue_t queue,void *context,dispatch_function_t work);
queue:指定执行该work的队列
void *context:所使用的 application-defined(应用程序范围内有效的,也就是全局的)级别的参数。这是个C语法,void * 是一个无类型指针。也就是说,用它可以指向任何内存数据。
work:在指定队列(queue 参数)中要执行的方法。在该方法中,第一个参数所指代的数据,也就是dispatch_async_f方法所使用的第二个参数(void *context)所指带的数据。
// 定义结构体
typedef struct{
char *title;
char *message;
char *cancelButtonTitle;
} AlertViewData;
// 定义dispatch_function_t 所执行的方法
void displayAlertView(void *paramContext){
AlertViewData *alertData = (AlertViewData *)paramContext;
NSString *title =[NSString stringWithUTF8String:alertData->title];
NSString *message =[NSString stringWithUTF8String:alertData->message];
NSString *cancelButtonTitle =[NSString stringWithUTF8String:alertData->cancelButtonTitle];
[[[UIAlertView alloc] initWithTitle:title message:message
delegate:nil
cancelButtonTitle:cancelButtonTitle otherButtonTitles:nil,nil] show];
// 释放结构体所占用的内存
free(alertData);
}
// **执行dispatch_async_f
dispatch_queue_t mainQueue = dispatch_get_main_queue();
// 为结构体分配内存
AlertViewData *context = (AlertViewData *) malloc(sizeof(AlertViewData));
// 初始化结构体
if (context != NULL){
context->title = "GCD";
context->message = "GCD is amazing.";
context->cancelButtonTitle = "OK";
// GCD执行异步方法:指定主队列(mainQueue),传递结构体数据(context)来执行displayAlertView方法。
dispatch_async_f(mainQueue,(void *)context, displayAlertView);
}
dispatch_async 方法
void dispatch_async(dispatch_queue_t queue,dispatch_block_t block);
dispatch_queue_t mainQueue1 = dispatch_get_main_queue();
dispatch_async(mainQueue1, ^(void) {
NSLog(@"Current thread = %@", [NSThread currentThread]);
NSLog(@"Main thread = %@", [NSThread mainThread]);
});
输出:
2013-03-27 15:45:54.501 DemoVideo[21802:707] Current thread = {name = (null), num = 1}
2013-03-27 15:45:54.503 DemoVideo[21802:707] Main thread = {name = (null), num = 1}
可见,dispatch_get_main_queue() 队列所执行的Block就是在主线程上执行的。
例如,你想下载一个图片并想在下载完成之后展现给用 户。下载过程却和 UI 没有任何关系。对于任何与 UI 无关的任务,你可以使用 GCD 中的全 局并发队列。它们允许同步和异步执行。如果你同步提交一个任务到一个并发队列,同时提交另一个同步任务到另一个并发队列;相对而言这两个同步任务将异步运行,因为他们运行在两个不同的并发队 列上。你想确定在 B 任务开始之前 A 任务完 成了。那么必须把它们同时提交一个相同的队列。
dispatch_get_global_queue 方法
dispatch_queue_t dispatch_get_global_queue(long priority,unsigned long flags);
priority:优先级
flags:暂时还没有用到,为0.
#define DISPATCH_QUEUE_PRIORITY_HIGH 2
#define DISPATCH_QUEUE_PRIORITY_DEFAULT 0
#define DISPATCH_QUEUE_PRIORITY_LOW (-2)
#define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN
dispatch_sync 方法
void dispatch_sync(dispatch_queue_t queue,dispatch_block_t block);
queue:指定的队列
block:执行的代码Block
// 得到默认优先级队列
dispatch_queue_t concurrentQueue =dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_sync(concurrentQueue, printFrom1To1000);// 同步执行
dispatch_sync(concurrentQueue, printFrom1To1000);// 同步执行
// 同步执行的Block
void (^printFrom1To1000)(void) = ^{
NSUInteger counter = 0;
for (counter = 1;counter <= 1000;counter++){
NSLog(@"Counter = %lu - Thread = %@",(unsigned long)counter, [NSThreadcurrentThread]);
}
};
在主队列、串行队列和并发队列上异步执行代码块才能见识到 GCD 的真正实力。你将会完全相信 GCD 是多线程应用的未来,并将完全取代 现代应用中的线程。
- (void) viewDidAppear:(BOOL)paramAnimated{
dispatch_queue_t concurrentQueue =dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(concurrentQueue, ^{
__block UIImage *image = nil;
dispatch_sync(concurrentQueue, ^{
// 同步下载图片
NSString *urlAsString =@"http://images.apple.com/mobileme/features/images/ipad_findyouripad_20100518.jpg";
NSURL *url = [NSURL URLWithString:urlAsString];
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
NSError *downloadError = nil;
NSData *imageData = [NSURLConnectionsendSynchronousRequest:urlRequest
returningResponse:nil
error:&downloadError];
if (downloadError == nil && imageData != nil){
image = [UIImage imageWithData:imageData];
}else if (downloadError != nil){
NSLog(@"Error happened = %@", downloadError);
} else {
NSLog(@"No data could get downloaded from the URL."); }
});
dispatch_sync(dispatch_get_main_queue(), ^{
// 直到下载图片完成,再调用主线程,更新UI
if (image != nil){
UIImageView *imageView = [[UIImageView alloc]initWithFrame:self.view.bounds];
[imageView setImage:image];
[imageView setContentMode:UIViewContentModeScaleAspectFit];
[self.view addSubview:imageView];
} else {
NSLog(@"Image isn't downloaded. Nothing to display.");
}
});
});
}
- (void)viewDidLoad{
[super viewDidLoad];
[self performSelector:@selector(printString:)
withObject:@"Grand Central Dispatch"
afterDelay:3.0];
}
- (void) printString:(NSString *)paramString{
NSLog(@"%@", paramString);
}
void dispatch_after(dispatch_time_t when,dispatch_queue_t queue,dispatch_block_t block);
when:所指定的时间
queue:指定的队列
block:执行的Block
- (void)viewDidLoad{
[super viewDidLoad];
double delayInSeconds = 2.0;
// 创建延期的时间 2S,因为dispatch_time使用的时间是纳秒,尼玛,比毫秒还小,太夸张了!!!
dispatch_time_t delayInNanoSeconds =dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
// 得到全局队列
dispatch_queue_t concurrentQueue =dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// 延期执行
dispatch_after(delayInNanoSeconds, concurrentQueue, ^(void){
NSLog(@"Output GCD !");
});
}
dispatch_time 方法
dispatch_time_t dispatch_time(dispatch_time_t when,int64_t delta);
when:指定的开始点,可以用 DISPATCH_TIME_NOW 来指定一个当前的时间点
delta:纳秒数
dispatch_after 方法
void dispatch_after(dispatch_time_t when,dispatch_queue_t queue,dispatch_block_t block);
when:时间点
queue:指定的队列
block:执行的Block
dispatch_after_f 方法
- (void)viewDidLoad{
[super viewDidLoad];
double delayInSeconds = 2.0;
dispatch_time_t delayInNanoSeconds =dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_queue_t concurrentQueue =dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_after_f(delayInNanoSeconds,concurrentQueue, @"GCD",processSomething);
}
void processSomething(void *paramContext){
NSLog(@"This is %@",paramContext);
}
static dispatch_once_t onceToken;
void (^executedOnlyOnce)(void) = ^{
static NSUInteger numberOfEntries = 0;
numberOfEntries++;
NSLog(@"Executed %lu time(s)", (unsigned long)numberOfEntries);
};
dispatch_queue_t concurrentQueue =dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_once(&onceToken, ^{
dispatch_async(concurrentQueue,executedOnlyOnce);
});
dispatch_once(&onceToken, ^{
dispatch_async(concurrentQueue,executedOnlyOnce);
});
dispatch_once 方法
void dispatch_once(dispatch_once_t *predicate,dispatch_block_t block);
predicate:单例标识符
block:执行的Block
dispatch_group_t 方法
typedef struct dispatch_group_s *dispatch_group_t;
dispatch_group_create 方法
dispatch_group_t dispatch_group_create(void);
创建一个调度组
dispatch_group_async 方法
void dispatch_group_async(dispatch_group_t group,dispatch_queue_t queue,dispatch_block_t block);
group:要分发到的调度组
queue:执行Block的队列
block:要执行的Block
将Block分发到指定的队列(用指定的队列来执行Block),并且将该Block加入到指定的调度组中。
dispatch_group_notify 方法
void dispatch_group_notify(dispatch_group_t group,dispatch_queue_t queue,dispatch_block_t block);
当调度组中的所有Block被执行完成后,将调用被分配到指定队列的Block。
dispatch_release 方法
void dispatch_release(dispatch_object_t object);
object:调度对象
销毁指定的调度组。
- (void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
dispatch_group_t taskGroup = dispatch_group_create();// 创建一个调度组
dispatch_queue_t mainQueue = dispatch_get_main_queue();// 创建队列
// 任务1
// 将Block添加到指定的调度组(taskGroup)中,并且该Block用指定的队列(mainQueue)执行。
dispatch_group_async(taskGroup, mainQueue, ^{
[self reloadTableView];
});
// 任务2
// 将Block添加到指定的调度组(taskGroup)中,并且该Block用指定的队列(mainQueue)执行。
dispatch_group_async(taskGroup, mainQueue, ^{
[self reloadScrollView];
});
// 任务3
// 将Block添加到指定的调度组(taskGroup)中,并且该Block用指定的队列(mainQueue)执行。
dispatch_group_async(taskGroup, mainQueue, ^{
[self reloadImageView];
});
// 当指定调度组(taskGroup)中的所有Block都执行完成后,将执行给定的Block,用指定的队列(mainQueue)。
dispatch_group_notify(taskGroup, mainQueue, ^{
// 指定的Block
[[[UIAlertView alloc] initWithTitle:@"Finished"
message:@"All tasks are finished"delegate:nil
cancelButtonTitle:@"OK" otherButtonTitles:nil, nil]show];
});
// 最后,必须release 掉调度组(taskGroup)
dispatch_release(taskGroup);
#pragma mark - 执行的多个方法
- (void) reloadTableView{
NSLog(@"%s", __FUNCTION__);
}
- (void) reloadScrollView{
NSLog(@"%s", __FUNCTION__);
}
- (void) reloadImageView{
NSLog(@"%s", __FUNCTION__);
}
2013-03-28 23:00:57.394 DemoVideo[25096:707] -[MoreViewController reloadTableView]
2013-03-28 23:00:57.395 DemoVideo[25096:707] -[MoreViewController reloadScrollView]
2013-03-28 23:00:57.396 DemoVideo[25096:707] -[MoreViewController reloadImageView]
- (void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
dispatch_group_t taskGroup = dispatch_group_create();
dispatch_queue_t mainQueue = dispatch_get_main_queue();
dispatch_group_async_f(taskGroup, mainQueue,(void *)self,reloadAllComponents);
dispatch_group_notify(taskGroup, mainQueue, ^{
[[[UIAlertView alloc] initWithTitle:@"Finished"
message:@"All Tasks are Finished"
delegate:nil
cancelButtonTitle:@"OK" otherButtonTitles:nil, nil] show];
});
dispatch_release(taskGroup);
}
// 定义调度组要执行的C函数
void reloadAllComponents(void *context){
MoreViewController *self =(MoreViewController *)context;
[self reloadTableView];
[self reloadScrollView];
[self reloadImageView];
}
- (void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
// 创建指定的自定义的串行队列
dispatch_queue_t firstSerialQueue =dispatch_queue_create("com.pixolity.GCD.serialQueue1", NULL);
// 让队列异步执行Block
dispatch_async(firstSerialQueue, ^{
NSUInteger counter = 0;
for (counter = 0; counter < 5; counter++){
NSLog(@"First iteration, counter = %lu", (unsigned long)counter); }
NSLog(@"Current thread = %@", [NSThread currentThread]);
});
dispatch_async(firstSerialQueue, ^{
NSUInteger counter = 0; for (counter = 0;counter < 5;counter++){
NSLog(@"Second iteration, counter = %lu", (unsigned long)counter);
NSLog(@"Current thread = %@", [NSThread currentThread]);
}
});
dispatch_async(firstSerialQueue, ^{ NSUInteger counter = 0;
for (counter = 0;counter < 5;counter++){
NSLog(@"Third iteration, counter = %lu", (unsigned long)counter);
NSLog(@"Current thread = %@", [NSThread currentThread]);
}
});
// 销毁队列
dispatch_release(firstSerialQueue);
// 输出主队列,比较会发现,我们自定义的队列,并不在主线程上,效率还是蛮高的。
dispatch_queue_t mainQueue1 = dispatch_get_main_queue();
dispatch_async(mainQueue1, ^(void) {
NSLog(@"Main thread = %@", [NSThread mainThread]);
});
}
// 定义任务1-C函数形式
void firstIteration(void *paramContext){
NSUInteger counter = 0;
for (counter = 0;counter < 5;counter++){
NSLog(@"First iteration, counter = %lu", (unsigned long)counter);
}
}
// 定义任务2-C函数形式
void secondIteration(void *paramContext){
NSUInteger counter = 0;
for (counter = 0;counter < 5;counter++){
NSLog(@"Second iteration, counter = %lu", (unsigned long)counter);
}
}
// 定义任务3-C函数形式
void thirdIteration(void *paramContext){
NSUInteger counter = 0;
for (counter = 0;counter < 5;counter++){
NSLog(@"Third iteration, counter = %lu", (unsigned long)counter);
}
}
- (void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
dispatch_queue_t firstSerialQueue =dispatch_queue_create("com.pixolity.GCD.serialQueue1", 0);
dispatch_async_f(firstSerialQueue, NULL, firstIteration);
dispatch_async_f(firstSerialQueue, NULL, secondIteration);
dispatch_async_f(firstSerialQueue, NULL, thirdIteration);
dispatch_release(firstSerialQueue);
}
dispatch_semaphore_create 方法
dispatch_semaphore_t dispatch_semaphore_create(long value);
创建一个信号量对象
value:信号量的值,必须大于等于0。
什么是信号量?
我想举个例子你就会明白了。古时候执行某种命令需要令牌。创建一个信号量,就是创建一个命令。
dispatch_semaphore_t semaphore = dispatch_semaphore_create(3);
也就是说,一项任务semaphore,有3个令牌,就是说,最多可以同时分派3名不同的将领去执行。
dispatch_semaphore_wait
Waits for (decrements) a semaphore.
long dispatch_semaphore_wait(dispatch_semaphore_t dsema,dispatch_time_t timeout);
递减信号量。
dsema:信号量
timeout:等待信号量的策略
返回0,说明递减信号量成功。
也就是说,拿走一个令牌去执行某个任务。这时候,令牌数量会减去1。当令牌用完时,使用FIFO的原则进行等待。
dispatch_semaphore_signal
long dispatch_semaphore_signal(dispatch_semaphore_t dsema);
增加信号量
也就是说,某一个将领执行任务回来。并且将令牌上交。这样处于等待中的将领可以得到令牌并执行相应任务。
//主线程中
TestObj *obj = [[TestObj alloc] init];
dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
//线程1
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
long thecount= dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
NSLog(@"%ld",thecount);
[obj method1];
sleep(10);
dispatch_semaphore_signal(semaphore);
});
//线程2
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
sleep(1);
long thecount= dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
NSLog(@"----%ld",thecount);
[obj method2];
dispatch_semaphore_signal(semaphore);
});