多线程

  多线程只要分为4种:pthread、NSThread、GCD、NSOperation;通常我们使用的是后面3种。经常会使用到的就是GCD和NSOperation。

pthread:
用C语言写的、生命周期由程序员自己管理、基本上使用不到。

  • 一套通用的多线程API;
  • 适用于Unix、Linux、Windows等系统;
  • 跨平台、可移植;
  • 适用难度大;

NSThread:
用OC语言写的、生命周期由程序员自己管理、偶尔会使用到。

  • 使用更加面向对象;
  • 简单易用,可直接操作线程对象;

GCD:
用C语言写的、生命周期自动管理、经常使用。

  • 用于替代NSThread等线程技术;
  • 充分利用设备多核;
  • 跨平台、可移植;
  • 适用难度大;

NSOperation:
用OC语言写的、生命周期自动管理、经常使用。

  • 基于GCD(底层是GCD);
  • 比GCD多了一些简单实用的功能;
  • 使用更加面向对象;

一、GCD的常用函数

1、同步线程(sync):只能是依次执行,不存才并发队列;(注意:不要炸当前串行队列中添加任务,会卡住当前串行队列,产生死锁。比如主线程(sync),中添加主队列任务)
  通常使用的是dispathch_sync(dispathch_queue_t queue, dispathch_block_t block)这个函数。
  queue:就是队列;
  block:就是你要做的事情,也就是任务;
2、异步线程(async):需要分为 并发队列串行队列
  通常使用的是dispathch_async(dispathch_queue_t queue, dispathch_block_t block)这个函数。
  queue:就是队列;
  block:就是你要做的事情,也就是任务;

  • 同步和异步区别就在于是否具备开启新线程的能力。(注意:如果你在主队列,你还是一个一个执行,不会去开新的线程,就算是用主队列,也不会产生死锁)
  • 在子线程中默认是没有开启RunLoop的。带有延迟、定时器,都是不会执行的。除非你打开RunLoop。
- (void)test {
  NSLog(@"2");
}

dispathch_queue_t queue = dispathch_get_global_queue(0,0);
dispathch_async(queue, ^{
  NSLog(@"1");
  [self performSelector:@selector(test) withObject:nil afterDelay:.0];
  NSLog(@"3");
}
这里的打印结果就是 1和3。延迟调用是在RunLoop里面的,默认子线程是没有开启子线程的。如果在主线里面是可以打印的,结果是132

dispathch_queue_t queue = dispathch_get_global_queue(0,0);
dispathch_async(queue, ^{
  NSLog(@"1");
  //  [self performSelector:@selector(test) withObject:nil];
  // 这两个是不一样的,这个是objc_msgsend里面的
  [self performSelector:@selector(test) withObject:nil afterDelay:.0];
  NSLog(@"3");
  // 这个可以不要,上面的方法是在RunLoop里面添加了定时器的。
  [[NSRunLoop currrentRunLoop] addPort:[[NSPort alloc] init] forMode:NSDefaultRunLoopMode];
  [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
}
这个打印的结果就是132

3、并发队列:多个任务同时执行。
4、串行队列(FIFO先进先出):一个任务执行完之后,才能执行下一个任务。
队列决定一个一个执行,还是多个一起执行。
点击查看GCD源码

思考:使用GCD实现:
  异步并发执行 任务1、任务2;
  等 任务1、任务2 完成之后再回到主线程执行 任务3。
// 创建队列组
dispathch_group_t group = dispathch_group_create();
// 创建并发队列
dispathch_queue_t queue = dispathch_queue_create("my_queue", DISPATHCH_CONCURRENT);

dispathch_group_async(group, queue, ^{
  for(init i = 0; i<5; i++) {
    NSLog(@"任务1-%@", [NSThread currentThread]);
  }
}
dispathch_group_async(group, queue, ^{
  for(init i = 0; i<5; i++) {
    NSLog(@"任务2-%@", [NSThread currentThread]);
  }
}
// 等前面任务完成之后,会自动执行这个任务
dispathch_group_notify(group, dispathch_get_main_queue(), ^{
  for(init i = 0; i<5; i++) {
    NSLog(@"任务3-%@", [NSThread currentThread]);
  }
}

二、多线程的安全问题

  • 资源共享
    • 一个资源被多个线程共享,也就是多个线程可能会访问同一个资源
    • 比如:多个线程访问同一个对象,同一个变量,同一个文件;
  • 当多个线程访问同一块资源时,很容易引发 数据错乱数据安全 问题

解决方案:

  • 使用 线程同步 技术(同步,就是协同步调,按预定的先后次序进行运行);
  • 常见的线程同步技术是:加锁;
  • OSSpinLock:自旋锁。等带锁的线程会处于忙等(busy-wait)状态,一直占用着CPU资源;线程不安全,优先级反转。
  • os_unfair_lock:互斥锁,用来替换自旋锁。处于休眠状态,不是忙等状态。
  • pthread_mutex:跨平台。等待锁的线程会处于休眠状态。
  • dispathch_semaphore:信号量,用来控制线程并发量。值为1,可以保证线程同步
  • dispathch_queue(DISPATHCH_QUEUE_SERIAL)GCD同步队列,也可以保证线程同步
  • NSLock:对mutex普通锁的封装。
  • NSRecursiveLock:对mutex的 *递归锁 封装。APINSLock基本一致。
  • NSCondition:对mutex和condition的封装。条件锁。
  • NSCondtionLock:对NSCondition的进一步封装,可以设置具体的条件值。条件值为1,也可以保证线程同步。
  • @synchronized:对mutex递归锁的封装,Apple不推荐使用,性能比较差。

性能从高到低排序

  • os_unfair_lock:iOS10以后,推荐使用
  • OSSpinLock
  • dispatch_semaphore:推荐使用
  • pthread_mutex:推荐使用
  • dispatch_queue(DISPATCH_QUEUE_SERIAL)
  • NSLock
  • NSCondition
  • pthread_mutex(recursive)
  • NSRecursiveLock
  • NSConditionLock
  • @synchronized

我们想写一个基类MJBaseDemo
MJBaseMode.h

#import 

@interface MJbaseMode : NSObject

- (void)moneyTest;
- (void)ticketTest;

#pragma mark - 暴露给子类去使用
- (void)__saveMoney;
- (void)__drawMoney;
- (void)__saleTicket;

@end

MJBaseMode.m

#import "MJBaseDemo.h"

@interface MJBaseDemo() 
@property (assign, nonatomic) int money;
@property (assign, nonatomic) int ticketsCount;
@end

@implementation MJBaseDemo
/** 卖票演示 */
- (void)ticketTest 
{
    self.ticketsCount = 15;
    dispathch_queue_t queue = dispathch_get_global_queue(0,0);
    dispathch_async(queue, ^{
        for (int i = 0; i < 5; ++i)
        {
            [self saleTicket];
        }
    }
    dispathch_async(queue, ^{
        for (int i = 0; i < 5; ++i)
        {
            [self saleTicket];
        }
    }
    dispathch_async(queue, ^{
        for (int i = 0; i < 5; ++i)
        {
            [self saleTicket];
        }
    }
}
- (void)monyeTest
{
    self.money = 100;
    dispathch_queue_t queue = dispathch_get_global_queue(0,0);
    dispathch_async(queue, ^{
        for (int i = 0; i < 10; ++i)
        {
            [self saveMoney];
        }
    }
    dispathch_async(queue, ^{
        for (int i = 0; i < 10; ++i)
        {
            [self drawMoney];
        }
    
}
// 卖票
- (void)__saleTicket 
{
    sleep(.2);
    self.ticketsCount --;
    NSLog(@"卖出一张票,还剩%d张----%@", self.ticketsCount, [NSThread currentThread]);
}

// 取钱
- (void)__drawMoney
{
    sleep(.2);
    self.money -= 20;
    NSLog(@"取钱20,还剩%d元----%@", self.money, [NSThread currentThread]);
}
// 存钱
- (void)__saveMoney
{
    sleep(.2);
    self.money += 50;
    NSLog(@"存钱50,还剩%d元----%@", self.money, [NSThread currentThread]);
}
@end

1、OSSpinLock:不推荐使用,效率还是很高的。

  • 等带锁的线程会处于忙等(busy-wait)状态,一直占用着CPU资源;
  • 需要导入头文件#import
  • 目前已经不再安全, 可能会出现优先级反转问题;
    • 如果等待锁的线程优先级比较高,他会一直占用CPU资源,优先级低的线程无法释放锁;

OSSpinLockDemo.h

#import "MJBaseDemo.h"

@interface OSSpinLockDemo : MJBaseDemo

@end

OSSpinLockDemo.m

#import "OSSpinLockDemo.h"
#import 

static OSSpinLock moneyLock_;
static OSSpinLock ticketLock_;

@interface OSSpinLockDemo()
// @property (assign, nonatomic) OSSpinLock moneyLock;
// @property (assign, nonatomic) OSSpinLock ticketLock;
@end

@implementation OSSpinLockDemo
+ (void)initialize {
    static dispathch_once_t onceToken;
    dispathch_once(&onceToken, ^{
        moneyLock_ = OS_SPINLOCK_INIT;
        ticketLock_ = OS_SPINLOCK_INIT;
    });
}

- (void)__saveMoney {
    OSSpinLockLock(&moneyLock_);
    [super __saveMoney];
    OSSpinLockUnlock(&moneyLock_);

}
- (void)__drawMoney {
    OSSpinLockLock(&moneyLock_);
    [super __drawMoney];
    OSSpinLockUnlock(&moneyLock_);
}
- (void)__saleTicket {
    OSSpinLockLock(&ticketLock_);
    [super __saleTicket];
    OSSpinLockUnlock(&ticketLock_);
}
@end

viewController.m

#import "ViewController.h"
#import "MJBaseDemo.h"
#import "MJOSSpinLock.h"
#import "OSSpinLockDemo.h"

@interface ViewController()
@property (strong, nonatomic) MJBaseDemo * demo;
@end

@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];

    MJBaseDemo * demo = [[OSSpinLockDemo alloc] init];
    [demo ticketTest];
    [demo moneyTest];
}
@end

2、os_unfair_lock:用于取代不安全的OSSpinLock, 从iOS10开始才支持。(Low-level lock低级锁会去休眠,可以看做互斥锁)

  • 从底层调用来看,等待os_unfair_lock锁的线程处于休眠状态,并不忙等。
  • 需要导入头文件#import
  • 这个不是 “自旋锁”,等待的线程会自动跳过,休眠,应该叫“互斥锁”

用法给OSSpinLock一样,只是头文件,和名字不一样。
如果os_unfair_look忘记解锁了,就会变成死锁。
SOUnfairLockDemo.h

#import "MJBaseDemo.h"
@interface SOUnfairLockDemo : MJBaseDemo
@end

SOUnfairLockDemo.m

#import "OSUnfairLockDemo.h"
#import 

static os_unfair_lock moneyLock_;
static os_unfair_lock ticketLock_;
@implementation OSUnfairLockDemo 
+ (void)initialize {
    static dispathch_once_t onceToken;
    dispathch_once(&onceToken, ^{
        moneyLock_ = OS_UNFAIR_LOCK_INIT;
        ticketLock_ = OS_UNFAIR_LOCK_INIT;
    });
}
- (void)__saveMoney {
    os_unfair_lock_lock(&moneyLock_);
    [super __saveMoney];
    os_unfair_lock_unlock(&moneyLock_);
}
- (void)__drawMoney {
    os_unfair_lock_lock(&moneyLock_);
    [super __drawMoney];
    os_unfair_lock_unlock(&moneyLock_);
}
- (void)__saleTicket {
    os_unfair_lock_lock(&ticketLock_);
    [super __saleTicket];
    os_unfair_lock_unlock(&ticketLock_);
}
@end

viewController.m

#import "ViewController.h"
#import "MJBaseDemo.h"
#import "SOUnfairLockDemo.h"

@interface ViewController()
@property (strong, nonatomic) MJBaseDemo * demo;
@end

@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];

    MJBaseDemo * demo = [[SOUnfairLockDemo alloc] init];
    [demo ticketTest];
    [demo moneyTest];
}
@end

3、pthread_mutext:互斥锁,等待锁的线程会处于休眠状态。

  • 需要导入头文件#import
  • 需要消耗属性设置,销毁锁;
  • 如果你是递归,或者重复使用一个锁,设置属性的时候,你选择递归锁(允许同一个线程使用同一把锁,第二个线程进入时,会等待第一个线程,完成之后,才会执行,去加锁;不会被第二个线程调用
#import "MutexDemo.h"
#import 


@interface MutexDemo()
@property (assign, nonatomic) pthread_mutex_t ticketMutex;
@property (assign, nonatomic) pthread_mutex_t moneyMutex;
@property (assign, nonatomic) pthread_mutex_t mutex;
@end

@implementation MutexDemo 
- (void)__initMutex:(pthread_mutex_t *)mutex {
    // 初始化属性
        pthread_mutexattr_t attr;
        pthread_mutexattr_init(&attr);
        pthread_mutexattr_settype(&attr, PTHEAD_MUTEX_DEFAULT);
        // 初始化锁
        pthread_mutex_init(mutex, &attr);
        // 销毁锁
        pthread_mutexattr_destroy(&attr);


        // 上面的可以替换
        // pthread_mutex_init(mutex, NULL);
        // 这个就是默认属性
}
- (void)__initMutex_recursive:(pthread_mutex_t *)mutex {
    // 初始化属性
        pthread_mutexattr_t attr;
        pthread_mutexattr_init(&attr);
        pthread_mutexattr_settype(&attr, PTHEAD_MUTEX_RECURSIVE);
        // 初始化锁
        pthread_mutex_init(mutex, &attr);
        // 销毁锁
        pthread_mutexattr_destroy(&attr);

        // PTHEAD_MUTEX_RECURSIVE 递归锁
        // 同一个线程会使用同一把锁,
        // 第二个线程进入时,会等待第一个线程,完成之后,才会执行,去加锁;
        // 不会被第二个线程调用。

        // PTHEAD_MUTEX_REEORCHECK 报错锁

        // PTHEAD_MUTEX_DEFAULT == PTHEAD_MUTEX_NORMAL 普通锁
}

- (instancetype)init {
    if (self = [super init])
    {
        [self __initMutex:&self.ticketMutex];
        [self __initMutex:&self.moneyMutex];
        [self __initMutex_recursive:&self.mutex];
    }
    return self;
}
- (void)__saveMoney {
    pthread_mutex_lock(&self.moneyMutex);
    [super __saveMoney];
    pthread_mutex_unlock(&self.moneyMutex);
}
- (void)__drawMoney {
    pthread_mutex_lock(&self.moneyMutex);
    [super __drawMoney];
    pthread_mutex_unlock(&self.moneyMutex);
}
- (void)__saleTicket {
    pthread_mutex_lock(&self.moneyMutex);
    [super __saleTicket];
    pthread_mutex_unlock(&self.moneyMutex);
}

- (void)otherTest {
    pthread_mutex_lock(&self.mutex);
    NSLog(@"@s", __func__);
    [self otherTest2];
    pthread_mutex_unlock(&self.mutex);
}
- (void)otherTest2 {
    pthread_mutex_lock(&self.mutex);
    NSLog(@"@s", __func__);
    pthread_mutex_unlock(&self.mutex);
}
- (void)dealloc {
    pthread_mutex_distroy(&slef.moneyMutex);
    pthread_mutex_distroy(&slef.ticketMutex);
    pthread_mutex_distroy(&slef.mutex);
}
@end

ViewController.m

#import "ViewController.h"
#import "MJBaseDemo.h"
#import "MJOSSpinLock.h"
#import "OSSpinLockDemo.h"
#import "OSUnfairLock.h"
#import "MutexDemo.h"

@interface ViewController()
@property (strong, nonatomic) MJBaseDemo * demo;
@end

@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];

    // MJBaseDemo * demo = [[OSSpinLockDemo alloc] init];

    // MJBaseDemo * demo = [[OSUnfairLock alloc] init];
    MJBaseDemo * demo = [[MutexDemo alloc] init];
    [demo ticketTest];
    [demo moneyTest];
    [demo otherTest];
}
@end

3-1、pthread_mutext:条件。

#import "MutexDemo.h"
#import 


@interface MutexDemo()
@property (assign, nonatomic) pthread_mutex_t condMutex;
@property (assign, nonatomic) pthread_cond_t cond;
@property (strong, nonatomic) NSMutableArray data;
@end

@implementation MutexDemo 
- (instancetype)init {
    if (self = [super init])
    {
        // 初始化属性
        pthread_mutexattr_t attr;
        pthread_mutexattr_init(&attr);
        pthread_mutexattr_settype(&attr, PTHEAD_MUTEX_RECURSIVE);
        // 初始化锁
        pthread_mutex_init(mutex, &attr);
        // 销毁锁
        pthread_mutexattr_destroy(&attr);

        // 初始化条件
        pthread_cond_init(&self.cond, NULL);

        self.data = [NSMutableArray array];
    }
    return self;
}


- (void)__add {
    pthread_mutex_lock(&self.condMutex);
    sleep(1);
    [self.data addObject:@"test"];
    NSLog(@"添加元素");
    // 发信号
    pthread_cond_signal(&self.cond);
    // 发广播,这个用于多线程,一次唤醒多个线程
    // pthread_cond_boradcast(&self.cond);

    pthread_mutex_unlock(&self.condMutex);
}
- (void)__remove {
    pthread_mutex_lock(&self.condMutex);
    NSLog(@"__remove - begin");
    if (self.data.count == 0)
    {
        pthread_cond_wait(&self.cond, &self.condMutex);
    }
    [self.data removeLastObject];
    NSLog(@"删除元素");
    pthread_mutex_unlock(&self.condMutex);
}

- (void)dealloc {
    pthread_mutex_destroy(&slef.condMutex);
    pthread_cond_destroy(&self.cond)
}
@end

4、NSLock :互斥锁。对pthead_mutext_t的封装,PTHREAD_MUTEX_NORMAL

#import "NSLockDemo.h"

@interface NSLockDemo()
@property (strong, nonatomic) NSLock * moneyLock;
@property (strong, nonatomic) NSLock * ticketLock;
@end

@implementation NSLockDemo 
- (instancetype)init {
    if (self = [super init])
    {
        // 相当于 pthread_mutext_init(&mutex,NULL)
        self.moneyLock = [[NSLock alloc] init];
        self.moneyLock = [[NSLock alloc] init];
    }
    return self;
}
- (void)__saveMoney {
    [self.moneyLock lock];
    [super __saveMoney];
    [self.moneyLock unlock];
}
- (void)__drawMoney {
    [self.moneyLock lock];
    [super __drawMoney];
    [self.moneyLock unlock];
}
- (void)__saleTicket {
    [self.ticketLock lock];
    [super __saleTicket];
    [self.ticketLock unlock];
}

@end

5、NSRecursiveLock:互斥锁。对pthead_mutext_t的封装,PTHREAD_MUTEX_RECURSIVE

  • 使用和NSLock一致。

6、NSCondition:条件。对mutext和cond的封装

#import "NSContitionDemo.h"

@interface NSContitionDemo()
@property (strong, nonatomic) NSCondition* condition;
@property (strong, nonatomic) NSMutableArray data;
@end

@implementation NSContitionDemo 
- (instancetype)init {
    if (self = [super init])
    {
        self.condition = [[NSCondition alloc] init];
        self.data = [NSMutableArray array];
    }
    return self;
}
- (void)__add {
    [self.condition lock];
    sleep(1);
    [self.data addObject:@"test"];
    NSLog(@"添加元素");
    [self.condition unlock];
    // 发信号
    [self.condition signal];
    // 广播
    // 【self.condition broadcast];
}
- (void)__remove {
    [self.condition lock];
    NSLog(@"__remove - begin");
    if (self.data.count == 0)
    {
        [self.condition wait];
    }
    [self.data removeLastObject];
    NSLog(@"删除元素");
    [self.condition unlock];
}

@end

7、NSConditionLock:条件。对NSCondition的进一步封装,可以设置条件

#import "NSContitionLockDemo.h"

@interface NSContitionLockDemo()
@property (strong, nonatomic) NSConditionLock * conditionLock;
@end

@implementation NSContitionLockDemo 
- (instancetype)init {
    if (self = [super init])
    {
        // 创建一个锁,条件为1
        self.conditionLock = [[NSConditionLock alloc] initWithCondition:1];
    }
    return self;
}
- (void)test {
    // 这里会先执行条件为1的锁,所在的线程
    [[[NSThread alloc] initWithTarget:self selector:@selector(__remove) object:nil] start];
    [[[NSThread alloc] initWithTarget:self selector:@selector(__add) object:nil] start];
}

- (void)__add {
    // 当条件为1时,加锁
    [self.conditionLock lockWhenCondition:1];
    NSLog(@"添加元素");
    // 解锁,修改条件为2
    [self.conditionLock unlockWithCondition:2];
}
- (void)__remove {
    // 当条件为2时,加锁
    [self.conditionLock lockWhenCondition:2];
    NSLog(@"删除元素");
    [self.conditionLock unlock];
}

@end

8、SerialQueue:同步串行队列,也能保证线程同步。

#import "SerialQueueDemo.h"

@interface SerialQueueDemo()
@property (strong, nonatomic) dispathch_queue_t  moneyQueue;
@property (strong, nonatomic) dispathch_queue_t * ticketQueue;
@end

@implementation SerialQueueDemo 
- (instancetype)init {
    if (self = [super init])
    {
        // 相当于 pthread_mutext_init(&mutex,NULL)
        self.moneyQueue = [dispathch_queue_create("moneyQueue", DISPATHCH_QUEUE_SERIAL)];
        self.ticketQueue = [dispathch_queue_create("ticketQueue", DISPATHCH_QUEUE_SERIAL)];
    }
    return self;
}
- (void)__saveMoney {
    dispathch_sync(self.moneyQueue, ^{
        [super __saveMoney];
    });
}
- (void)__drawMoney {
    dispathch_sync(self.moneyQueue, ^{
        [super __drawMoney];
    });
}
- (void)__saleTicket {
    dispathch_sync(self.ticketQueue, ^{
        [super __saleTicket];
    });
}
@end

9、dispathch_semaphore:信号量。

  • 信号量的初始值,可以用来控制线程并发访问的最大数量。
  • 如果信号量的值为1,也是能保证线程同步的。
#import "SemaphoreDemo.h"

@interface SemaphoreDemo()
@property (strong, nonatomic) dispthch_semaphore_t semaphore;
@end

@implementation SemaphoreDemo
- (instancetype)init {
    if (self = [super init])
    {
        // 最多只有5个线程执行任务。
        self.semaphore = dispthch_semaphore_create(5);
    }
    return self;
}
- (void)otherTest {
    // 同时开20个线程做一个事情
    for (int i = 0; i < 20; i++)
    {
        [[[NSThread alloc] initWithTarget:self selector:@selector(test) object:nil] start];
    }
}
- (void)test {
    // 如果信号量的值 > 0,就让信号量的值减1,然后继续往下执行代码
    // 如果信号量 <= 0,就会休眠,直到信号量的值 > 0,去抢到这个信号,接着继续让信号量的值减1, 然后继续往下执行代码
    dispthch_semaphore_wait(self.semaphore, DISPATHCH_TIME_FOREVER);

    sleep(1);
    NSLog(@"test---%@", [NSThread currentThread]);

    // 信号量的值 +1
    dispthch_semaphore_signal(self.semaphore);
}
@end

10、@synchronized:对mutex递归锁的封装

  • 性能比较差,官方不推荐使用。
#import "SerialQueueDemo.h"

@implementation SerialQueueDemo 
- (void)__saveMoney {
    // 确保self是同一个对象,才有加锁的功能。也可是类对象,[self class]
    @synchronized(self) {
        [super __saveMoney];
    }
}
- (void)__drawMoney {
    @synchronized(self) {
        [super __drawMoney];
    }
}
- (void)__saleTicket {
    static NSObjec * lock;
    static dispathch_once_t onceToken;
    dispathch_once(&onceToken, ^{
        lock = [[NSObjec alloc] init];
    });
    @synchronized(lock) {
        [super __saleTicket];
    }
}

@end

使用技巧,通过宏来简便使用。

#define SemaphoreBegin \
static dispathch_semaphore_t semaphore; \
static dispathch_once_t onceToken; \
dispathch_once(&onceToken, ^{ \
    semaphore = dispathch_semaphore_create(1); \
}); \
dispathch_semaphore_wait(semaphore, DISPATHCH_TIME_FOREVER);


#define SemaphoreeEnd \
dispathch_semaphore_signal(semaphore);



- (void)test {
    SemaphoreBegin;
    // ......do things......
    SemaphoreeEnd;
}

11、自旋锁和互斥锁比较

  • 什么情况使用自旋锁比较划算?
    • 预计线程等待锁的时间比较短;
    • 加锁的代码经常使用,但是竞争情况很少发生;
    • CPU资源不紧张;
    • 多核处理器。
  • 什么情况使用互斥锁比较划算?
    • 预计线程等待时间长,2s+;
    • 单核处理器;
    • 临界区(锁里面的开始代码,和结束代码)有I/O操作;
    • 临界区代码复杂或者循环量大;
    • 临界区竞争非常激烈。

12、I/O操作,文件操作、读写安全

  • 从文件中读取内容;
  • 往文件中写入内容;
    方案:
  • 同一时间,只能有1线程进行写的操作
  • 同一时间,允许多个线程进行操作
  • 同一时间,不允许既有写的操作,又有读的操作。

dispathch_rwlock:跨平台,读写锁

  • 等待锁的线程会进入睡眠;
#import "pthreadRwlockDemo.h"

@interface pthreadRwlockDemo()
@property (assign, nonatomic) pthread_rwlock_t lock;
@end

@implementation pthreadRwlockDemo
- (void)viewDidLoad {
    [super viewDidLoad];

    pthread_rwlock_init(&self.lock, NULL);

    dispathch_queue_t queue = dispathch_get_global_queue(0,0);
    for (int i = 0; i < 10; ++i)
    {
        dispathch_async(queue, ^{
            [self read];
        });
        dispathch_async(queue, ^{
            [self write];
        });

    }
}
- (void)read {
    pthread_rwlock_rdlock(&self.lock);
    sleep(1);
    NSLog(@"%s", __func__);
    pthread_rwlock_unlock(&self.lock);

}
- (void)write {
    pthread_rwlock_wrlock(&self.lock);
    sleep(1);
    NSLog(@"%s", __func__);
    pthread_rwlock_unlock(&self.lock);

}
- (void)dealloc {
    pthread_rwlock_destroy(&self.lock);
}
@end

dispathch_barrier_async:跨平台,读写锁

  • 这个函数传入的并发队列必须是自己通过dispathch_queue_create创建;
  • 如果传入是一个串行或者是一个全局的并发队列,那这个函数等同于dispathch_async函数的效果;
#import "pthreadBarrierDemo.h"

@interface pthreadBarrierDemo()
@property (strong, nonatomic) dispathch_queue_t queue;
@end

@implementation pthreadBarrierDemo
- (void)viewDidLoad {
    [super viewDidLoad];
    // 并发队列
    self.queue = dispathch_queue_create("rw_queue", DISPATHCH_QUEUE_CONCURRENT);

    for (int i = 0; i < 10; i++)
    {
        dispathch_async(queue, ^{
            [self read];
            [self read];
        });
        dispathch_barrier_async(queue, ^{
            [self write];
        });

    }
}
- (void)read {
    sleep(1);
    NSLog(@"%s", __func__);

}
- (void)write {
    sleep(1);
    NSLog(@"%s", __func__);

}
@end

你可能感兴趣的:(多线程)