iOS线程同步和锁

应用程序里面多个线程的存在引发了多个执行线程安全访问资源的潜在问题。两个线程同时修改同一资源有可能以意想不到的方式互相干扰。

iOS
提供了你可以使用的多个同步工具,从提供互斥访问你程序的有序的事件的工具等。以下个部分介绍了这些工具和如何在代码中使用他们来影响安全的访问程序的资源。

我们通过同一个例子来说明这些锁,当两个线程同时操作一个可变数组时,一个线程添加数据,一个线程删除数据,类似一个生产消费者模式,就会存在线程安全问题;

使用POSIX互斥锁

__block pthread_mutex_t mutex;
    pthread_mutex_init(&mutex,NULL);
    __block NSMutableArray* products = [[NSMutableArray alloc]init];

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

        while (YES) {

            pthread_mutex_lock(&mutex);

            [products addObject:@"product"];

            pthread_mutex_unlock(&mutex);
        }

    });

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

        while (YES) {
            pthread_mutex_lock(&mutex);

            if (products.count != 0) {
                [products removeObjectAtIndex:0];
            }

            pthread_mutex_unlock(&mutex);

        }

    });

使用NSLock类


Cocoa
程序中
NSLock
中实现了一个简单的互斥锁。所有锁(包括
NSLock)的接口实际上都是通过
NSLocking
协议定义的,它定义了
lock

unlock
方法。你使用这些方法来获取和释放该锁。

除了标准的锁行为,NSLock
类还增加了
tryLock

lockBeforeDate:方法。方法tryLock
试图获取一个锁,但是如果锁不可用的时候,它不会阻塞线程。相反,它只是返回
NO。而
lockBeforeDate:方法试图获取一个锁,但是如果锁没有在规定的时间内被获得,它会让线程从阻塞状态变为非阻塞状态(或者返回
NO)。

NSLock* lock = [[NSLock alloc]init];
    __block NSMutableArray* products = [[NSMutableArray alloc]init];

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

        while (YES) {
            [lock lock];

            [products addObject:@"product"];

            [lock unlock];

            /*避免阻塞*/
            /*
            if([lock tryLock])
            {
                [products addObject:@"product"];

                [lock unlock];
            }
             */
        }

    });

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

        while (YES) {
            [lock lock];

            if (products.count != 0) {
                [products removeObjectAtIndex:0];
            }

            [lock unlock];

        }

    });

使用@synchronized指令

@synchronized
指令是在
Objective-C
代码中创建一个互斥锁非常方便的方法。@synchronized
指令做和其他互斥锁一样的工作(它防止不同的线程在同一时间获取同一个锁)。然而在这种情况下,你不需要直接创建一个互斥锁或锁对象。相反,你只需要简单的使用
Objective-C
对象作为锁的令牌

__block NSMutableArray* products = [[NSMutableArray alloc]init];

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

        @synchronized(products)
        {
            while (YES) {

                [products addObject:@"product"];
            }
        }

    });

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

        @synchronized(products)
        {
            while (YES) {

                if (products.count != 0) {
                    [products removeLastObject];
                }

            }
        }

    });

使用单例的时候

@interface SingleObject : NSObject

@property (strong, nonatomic) NSMutableArray *products;

+ (instancetype)sharedInstance;

- (void)addmethod;

- (void)removemethod;

@end

@implementation SingleObject

+ (instancetype)sharedInstance
{
    static SingleObject *sharedInstance_ = nil;
    static dispatch_once_t oncePredicate;
    dispatch_once(&oncePredicate, ^{
        sharedInstance_ = [[[self class] alloc] init];
    });

    return sharedInstance_;
}

- (id)init
{
    self = [super init];
    if (self)
    {
        self.products = [[NSMutableArray alloc]init];
    }

    return self;
}

- (void)addmethod
{
    [self.products addObject:@"product"];
}

- (void)removemethod
{
    if (self.products.count != 0) {
        [self.products removeObjectAtIndex:0];
    }
}

@end
SingleObject *object = [SingleObject sharedInstance];

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

        @synchronized(object)
        {
            while (YES) {

                [object addmethod];

            }

        }

    });

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

        @synchronized(object)
        {
            while (YES) {

                [object removemethod];

            }
        }

    });

使用
NSConditionLock
对象

NSConditionLock
对象定义了一个互斥锁,可以使用特定值来锁住和解锁。不要把该类型的锁和条件(NSCondition)混淆了。它的行为和条件有点类似,但是它们的实现非常不同。

#define HAS_DATA 1
#define NO_DATA 0

    NSConditionLock* condLock = [[NSConditionLock alloc] initWithCondition:NO_DATA];

    NSMutableArray* products = [[NSMutableArray alloc]init];

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

        while(1)
        {
            [condLock lock];
            [products addObject:@"product"];
            [condLock unlockWithCondition:HAS_DATA];

        }

    });

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

        while(1)
        {
            [condLock lockWhenCondition:HAS_DATA];
            [products removeLastObject];
            [condLock unlockWithCondition:(products.count == 0 ? NO_DATA : HAS_DATA)];

        }

    });

问题:以上的消费者都是在线程中轮询来去数据,这样会消耗大量cpu资源,如果可以在有数据的时候自己被告知,没有数据的时候空闲等待就好了,这时我们可以使用条件来完成,有以下两种方式(使用
POSIX
条件或者使用NSCondition类)。

使用NSCondition类

NSCondition
类提供了和
POSIX
条件相同的语义,但是它把锁和条件数据结构封装在一个单一对象里面。结果是一个你可以像互斥锁那样使用的对象,然后等待特定条件。

消费者取得锁,取产品,如果没有,则wait,这时会释放锁,直到有线程唤醒它去消费产品;

生产者制造产品,首先也是要取得锁,然后生产,再发signal,这样可唤醒wait的消费者

NSMutableArray* products = [[NSMutableArray alloc]init];
    NSCondition* condition = [[NSCondition alloc] init];

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//        消费者
        while(1)
        {
            [condition lock];

            while (products.count < 10) {
                [condition wait];
            }
            [products removeObjectAtIndex:0];

            [condition unlock];
        }

    });

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//        生产者
        while(1)
        {
            [condition lock];

            [products addObject:@"product"];

            [condition signal];

            [condition unlock];

        }

    });

-参考《多线程编程指南》

时间: 2024-08-29 22:22:47

iOS线程同步和锁的相关文章

iOS 线程同步 自旋锁 OSSpinLock

#import "ViewController.h" #import <libkern/OSAtomic.h> @interface ViewController () @property (nonatomic,assign) int ticket; //@property (nonatomic,assign) OSSpinLock lock; @end @implementation ViewController - (void)viewDidLoad { [super

线程同步与锁

二元信号量,多元信号量,互斥量,临界区.其它包括读写锁,条件变量. -1:二元信号量,适合与只能被一个线程独占访问的资源.当二元信号量处于非占用状态时,第一个试图获取该二元信号量的线程会获得该锁,并将二元信号量重置为占用状态,在未释放该锁前,其它所有试图获取该二元信号量的线程将会等待. -2:多元信号量,简称信号量.一个初始值为N的信号量允许N个线程并发访问. 获取该信号量时,信号量的值减一,当信号量的值小于0时,再来获取信号量的线程进入等待状态. 释放该信号量时,信号量的值加一,当信号量的值大

python笔记10-多线程之线程同步(锁lock)

前言 关于吃火锅的场景,小伙伴并不陌生,吃火锅的时候a同学往锅里下鱼丸,b同学同时去吃掉鱼丸,有可能会导致吃到生的鱼丸.为了避免这种情况,在下鱼丸的过程中,先锁定操作,让吃火锅的小伙伴停一会,等鱼丸熟了再开吃,那么python如何模拟这种场景呢? 未锁定 1.如果多个线程同时操作某个数据,会出现不可预料的结果.比如以下场景:当小伙伴a在往火锅里面添加鱼丸的时候,小伙伴b在同时吃掉鱼丸,这很有可能导致刚下锅的鱼丸被夹出来了(没有熟),或者还没下锅,就去夹鱼丸(夹不到). # coding=utf-

Linux线程同步---互斥锁

线程中互斥锁使用的步骤与信号量相似! 1.首先定义互斥锁变量,并初始化 pthread_mutex_t mutex_lock;pthread_mutex_init(&mutex_lock,NULL);2.在操作前对互斥量进行加锁操作 pthread_mutex_lock(&mutex_lock);3.操作完毕后进行解锁操作 pthread_mutex_unlock(&mutex_lock); 所有操作均在加锁和解锁操作之间进行,保证同时仅仅对有一个操作对关键变量或是区域进行操作.

线程同步--悲观锁

在做数据库访问的时候,遇到了这样的问题:两个线程同时访问同一对象中的方法,那么就可能会引发数据不一致的问题,那么我们需要做的,就是加上锁. 第一种方案:Synchronized Java中用来给对象和方法或者代码加锁的,当他锁定一个方法或者一个代码块的时候,同一时刻最多只有一个线程执行该代码.当两个并发线程访问同一个对象object中的这个加锁同步代码块时,一个时间内只有一个线程得到,另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块. 用法:Synchronized 加入方法上和S

Linux 线程编程2.0——线程同步-互斥锁

当我们需要控制对共享资源的存取的时候,可以用一种简单的加锁的方法来控制.我们可以创建一个读/写程序,它们共用一个共享缓冲区,使用互斥锁来控制对缓冲区的存取. 函数 pthread_mutex_init()用来生成一个互斥锁.其函数原型如下: #include<pthread.h> int pthread_mutex_init(pthread_mutex_t *restrict mutex,const pthread_mutexattr_t *restrict attr): 第一个参数是互斥变量

iOS 线程同步 NSLock、NSRecursiveLock、NSCondition

#import "ViewController.h" #import <pthread.h> @interface ViewController () @property (nonatomic, strong) NSCondition *lock; @property (nonatomic, strong) NSMutableArray *data; @end @implementation ViewController - (void)viewDidLoad { [sup

Linux线程同步

线程同步-互斥锁 1.初始化互斥锁pthread_mutex_init() int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr); 例: pthread_mutex_t mutex; pthread_mutex_init(&mutex, NULL); 2.锁住互斥锁pthread_mutex_lock() int pthread_mutex_lock(pt

9 C++ Boost 多线程,线程同步

线程的创建 boost_thread,boost_system 多线程的创建 线程的参数传递 线程的创建方式 线程的join 加入join,回收线程 线程中断 线程中断2, 线程组 boost 线程的死锁 boost 线程递归锁 线程互斥锁,线程同步 unique_lock 锁,离开作用域自动释放 unique_lock 锁 示例 2,可以显式的释放锁 boost 1次初始化 boost 条件变量 boost 线程锁,一个账户往另外一个账户转钱案例 boost upgrade_lock 知识背景