对于线程之间的同步,主要关心两个地方,一个是保证同一段代码在一段时间内只能被一个线程调用。@synchronized
另一个是保证变量或者资源的读写一次只能有一个线程操作。NSLock
先来看一个经典的案例:卖票
线程同步中我们经常使用的方法:@synchronized NSLock pthread_mutex_t
当然信号量这里也经常使用。
(1)@synchronized
首先我们模拟多个窗口
创建并行队列
dispatch_queue_t q =dispatch_queue_create("Ticket",DISPATCH_QUEUE_CONCURRENT);
dispatch_async(q, ^{
卖票窗口1
self SaleTicket:@"NO1"];
});
卖票窗口2
dispatch_async(q, ^{
selfSaleTicket:@"NO2"];
});
卖票代码:SaleTicket:
@synchronized(self) {
if (tickets >0) {
tickets--;
}
}
如果不加@synchronized关键词,代码中有可能出现同时卖同一张票的情况,这是一个典型的资源抢夺的案例。
同时卖票的这一段也可以专门放在一个特殊的类当中。调用类的静态方法+,或者使用类的单例。
(2)NSLOCK
比较以下下面两端代码:
mNSLock = [[NSLockalloc]init];
dispatch_async(dispatch_get_global_queue(0,0), ^{
// [mNSLock lock];
NSLog(@"A1");
[NSThreadsleepForTimeInterval:1];
NSLog(@"A2");
// [mNSLock unlock];
// [mNSLock lock];
NSLog(@"A3");
[NSThreadsleepForTimeInterval:1];
NSLog(@"A4");
// [mNSLock unlock];
});
dispatch_async(dispatch_get_global_queue(0,0), ^{
// [mNSLock lock];
NSLog(@"B1");
[NSThreadsleepForTimeInterval:1];
NSLog(@"B2");
// [mNSLock unlock];
// [mNSLock lock];
NSLog(@"B3");
[NSThreadsleepForTimeInterval:1];
NSLog(@"B4");
// [mNSLock unlock];
});
很显然,A12先执行,然后线程等待,这个B12获取锁的资源可以执行然后依次A34 B34.
(3)pthread_mutex_t
这个互斥锁的使用和上面的NSLock类似,这里是经常使用的几个方法:
pthread_mutex_t mutex;
pthread_mutex_init(&mutex, NULL);
pthread_mutex_lock(&mutex);
pthread_mutex_unlock(&mutex);
(4)下面介绍一个非常重要的
有时候我们在实际应用中,一方面会要求一段代码A在一个时间内只能被一个线程使用,同时在这段代码执行的过程中不能有其它线程对这段代码中的数据进行操作,或者对A进行修改。那么这个时候:
可以将@synchronized 和 NSLOCK。首先我们创建一个单例类,@synchronized(单例类)保证这段代码在一个时间段内只有一个线程在执行,同时我们吧这个单例类NSLOCK 。这样另一个@synchronized 2(单例类)就无法执行,一直到@synchronized(单例类)中的A代码执行完毕,调用NSUnLock 这个时候@synchronized 2(单例类)才可以执行。保证了这段代码在执行的过程中,其它线程不能对起进行数据修改等操作。
(5)信号量的使用
信号量中三个非常重要的方法:
dispatch_semaphore_create 创建一个semaphore
dispatch_semaphore_signal 发送一个信号
dispatch_semaphore_wait 等待信号
dispatch_semaphore_t semaphore = dispatch_semaphore_create(2);
比如这里创建了一个信号量,资源个数为2,表示可以使用2次。
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
如果信号量的资源个数>0,那么继续执行。并且信号量的资源个数减一。
如果信号量的资源个数<=0,那么代码一直等待,直到有资源可以使用。
dispatch_semaphore_signal(semaphore);