echo.hu

多线程笔记

每次看完就忘,还是总结下.

线程的创建

两种线程的创建方法

1
2
3
4
5
//获取全局并行线程,第一个参数为优先级
self.syscQueue=dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//串行队列创建,当第二个参数为DISPATCH_QUEUE_CONCURRENT时创建的是并行队列,多个串行队列可以并列执行.
dispatch_queue_t serialQueue=dispatch_queue_create("com.zxd.hwd", DISPATCH_QUEUE_SERIAL);

异步dispatch_async

把两个任务添加到全局队列里面让他们并行运行,因为最后一句输出语句是在主线程运行的,所以会与两个任务的线程并行运行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
//并行队列,队列里面的东西运行时串行的,队列之间是并行运行的
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
for (int i=0; i<5; i++) {
NSLog(@"并行First task %d",i);
sleep(1);
}
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
for (int j=0; j<5; j++) {
NSLog(@"并行Second task %d",j);
sleep(1);
}
});
NSLog(@"并行dispatch is over");
//串行队列
dispatch_queue_t serialQueue=dispatch_queue_create("com.zxd.hwd", DISPATCH_QUEUE_SERIAL);
dispatch_async(serialQueue, ^{
for (int i=0; i<5; i++) {
NSLog(@"串行First task %d",i);
sleep(1);
}
});
dispatch_async(serialQueue, ^{
for (int j=0; j<5; j++) {
NSLog(@"串行Second task %d",j);
sleep(1);
}
});
NSLog(@"串行dispatch is over");

同步dispatch_sync

在全局线程上面同步运行,第一个任务执行完毕才开始执行第二个任务.

1
2
3
4
5
6
7
dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"3333");
sleep(1);
});
dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"2333");
});

dispatch_after

延迟一段时间把一项任务提交到队列中执行

1
2
3
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"延迟");
});

dispatch_apply

把一项任务提交到队列中多次执行,具体是并行执行还是串行执行由队列本身决定.注意,dispatch_apply不会立刻返回,在执行完毕后才会返回,是同步的调用.

1
2
3
4
5
6
7
8
9
10
NSArray *list=@[@"hello",@"hwd",@"hello world"];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
dispatch_apply(3, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(size_t index) {
//相对主队列(主线程)是异步的,在global队列中是并行执行的
NSString *str=list[index];
NSLog(@"%lu",(unsigned long)str.length);
});
NSLog(@"Dispatch_after in global queue is over");
});
NSLog(@"Dispatch_after in main queue is over");

dispatch_once

1
2
3
4
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
//保证在APP运行期间,block中的代码只执行一次的代碼
});

dispatch_group_t

想要在所以并行线程执行完毕后执行某个任务通常用到dispatch_group_t

1
2
3
4
5
6
7
8
9
10
11
12
13
dispatch_group_t hwdGroup=dispatch_group_create();
//全局队列,这个队列为并行队列
dispatch_queue_t globalQueueDefault=dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//创建一个用户队列,这个队列为串行队列
dispatch_queue_t userCreateQueue=dispatch_queue_create("com.test.helloHwc",DISPATCH_QUEUE_SERIAL);
[self downLoadTask1:hwdGroup :globalQueueDefault];
[self downLoadTask2:hwdGroup :userCreateQueue];
[self downLoadTask3:hwdGroup :userCreateQueue];
dispatch_group_notify(hwdGroup, dispatch_get_main_queue(), ^{
NSLog(@"Group tasks are done");
});
NSLog(@"Now viewDidLoad is done");
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
-(void)downLoadTask1 :(dispatch_group_t)group :(dispatch_queue_t)queue{
dispatch_group_async(group, queue, ^{
sleep(3);
NSLog(@"Task1 is done");
});
}
-(void)downLoadTask2 :(dispatch_group_t)group :(dispatch_queue_t)queue{
dispatch_group_async(group, queue, ^{
sleep(3);
NSLog(@"Task2 is done");
});
}
-(void)downLoadTask3 :(dispatch_group_t)group :(dispatch_queue_t)queue{
dispatch_group_async(group, queue, ^{
sleep(3);
NSLog(@"Task3 is done");
});
}

dispatch_semaphore_create

通常用来控制并发线程的数量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//创建一个信号量dispatch_semaphore_create
//提高信号量dispatch_semaphore_signal
//等待降低信号量dispatch_semaphore_wait
self.semaphore=dispatch_semaphore_create(1);
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self task_first];
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self task_second];
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self task_third];
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
-(void)task_first{
//当信号总量少于0的时候就会一直等待,否则就可以正常的执行,并让信号总量-1
dispatch_semaphore_wait(self.semaphore, DISPATCH_TIME_FOREVER);
NSLog(@"First task starting");
sleep(1);
NSLog(@"First task is done");
//是发送一个信号,自然会让信号总量加1
dispatch_semaphore_signal(self.semaphore);
}
-(void)task_second{
dispatch_semaphore_wait(self.semaphore, DISPATCH_TIME_FOREVER);
NSLog(@"Second task starting");
sleep(1);
NSLog(@"Second task is done");
dispatch_semaphore_signal(self.semaphore);
}
-(void)task_third{
dispatch_semaphore_wait(self.semaphore, DISPATCH_TIME_FOREVER);
NSLog(@"Thrid task starting");
sleep(1);
NSLog(@"Thrid task is done");
dispatch_semaphore_signal(self.semaphore);
}

死锁

  • 死锁案例一
1
2
3
4
5
NSLog(@"1"); // 任务1
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"2"); // 任务2
});
NSLog(@"3"); // 任务3

因为任务2被同步添加进主线程,所以任务2需要等待任务3执行完毕后才能执行,而因为是同步任务3需要等待任务2执行完毕才能执行,所以造成主线程阻塞(死锁)。

  • 死锁案例二
1
2
3
4
5
6
7
8
9
10
11
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSLog(@"1"); // 任务1
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"2"); // 任务2
});
NSLog(@"3"); // 任务3
});
NSLog(@"4"); // 任务4
while (1) {
}
NSLog(@"5"); // 任务5

控制台输出:1 4 ,1和4的顺序不一定

线程案例

  • 线程案例一
1
2
3
4
5
6
7
8
9
10
11
dispatch_queue_t queue = dispatch_queue_create("com.demo.serialQueue", DISPATCH_QUEUE_SERIAL);
NSLog(@"1"); // 任务1
//把任务加入到队列queue最后面
dispatch_async(queue, ^{
NSLog(@"2"); // 任务2
dispatch_sync(queue, ^{
NSLog(@"3"); // 任务3
});
NSLog(@"4"); // 任务4
});
NSLog(@"5"); // 任务5

控制台输出:1 5 2 ,5和2的顺序不一定

  • 线程案例二
1
2
3
4
5
6
7
8
9
NSLog(@"1"); // 任务1
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSLog(@"2"); // 任务2
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"3"); // 任务3
});
NSLog(@"4"); // 任务4
});
NSLog(@"5"); // 任务5

1最先执行;2和5顺序不一定;4一定在3后面

  • 不要使用dispatch_get_current_queue()获取当前线程