iOS 锁总结(cc)

iOS锁机制详解

iOS中atomic和synchrosize锁的本质是什么?  

在iOS中,atomic@synchronized锁的本质涉及底层的多线程同步机制。以下是关于这两者本质的详细解释:

atomic

  1. 定义与用途

    • atomic是Objective-C属性修饰符的一种,用于指示属性的存取方法是线程安全的。
    • 当一个属性被声明为atomic时,编译器会生成线程安全的存取方法,以确保在多线程环境下该属性的访问不会导致数据竞争。
  2. 实现机制

    • 在Objective-C的运行时实现中(例如在objc4的实现里),atomic是通过自旋锁(spinlock_t)来实现的。
    • 当一个线程尝试获取或设置atomic属性时,它会先获取自旋锁,执行操作后释放锁。这确保了同一时间只有一个线程能够访问该属性。
  3. 性能与限制

    • 虽然atomic能提供线程安全性,但它并不保证复合操作的原子性。例如,先检查后执行(check-then-act)的操作仍然可能不安全。
    • atomic属性的存取操作相对于nonatomic会有更高的性能开销,因为涉及到锁的获取和释放。

https://blog.youkuaiyun.com/opentogether/article/details/144296336?sharetype=blogdetail&sharerId=144296336&sharerefer=PC&sharesource=opentogether&spm=1011.2480.3001.8118

@synchronized

  1. 定义与用途

    • @synchronized是Objective-C中的一个指令,用于创建一个互斥锁(mutex)来保护特定代码段的执行,防止多个线程同时执行该段代码。
    • 它用于确保一段代码在同一时间只能被一个线程执行,从而避免数据竞争和条件竞争。
  2. 实现机制

    • @synchronized指令内部使用了一个互斥锁(mutex)来实现同步。
    • 当线程进入@synchronized代码块时,会尝试获取锁。如果锁已经被其他线程持有,则当前线程会阻塞,直到锁被释放。
    • 一旦线程获取了锁,它就可以安全地执行@synchronized代码块中的代码。执行完毕后,锁会被自动释放。
    • 实现机制

      @synchronized 是基于 objc_sync 系列函数实现的。这些函数是由底层的 Runtime 提供的,主要包括:@synchronized 使用的锁是一种递归锁(recursive mutex

    • objc_sync_enter(id obj)
      • 当线程进入 @synchronized 块时,会调用 objc_sync_enter(obj)
      • 这个方法会尝试获取 obj 作为锁。
      • 如果其他线程已经持有这个锁,当前线程会阻塞直到锁释放。
    • objc_sync_exit(id obj)
      • 当线程退出 @synchronized 块时,会调用 objc_sync_exit(obj)
      • 这个方法会释放持有的锁,并唤醒等待的线程。
  3. 性能与限制

    • 使用@synchronized可以确保线程安全,但也会引入一定的性能开销,特别是在高并发场景下。
    • atomic不同,@synchronized可以用于保护更复杂的操作或代码段,而不仅仅是单个属性的存取。

总的来说,atomic@synchronized在iOS中都是用于实现线程同步的机制,但它们的用途和实现方式有所不同。atomic主要用于保护属性的线程安全存取,而@synchronized则用于保护更广泛的代码段免受并发访问的影响。

扩展:

iOS中atomic属性的作用是什么?

synchronized锁的使用场景有哪些?

atomic和synchronized有何不同?

自旋锁  

iOS中自己怎么实现一个自旋锁?

  

在iOS中,你可以使用OSSpinLock来实现自旋锁,但需要注意的是,从iOS 10和macOS 10.12开始,Apple已经弃用了OSSpinLock,因为它可能在高并发情况下导致优先级反转和其他问题。尽管如此,为了解释概念,我会首先展示一个基于OSSpinLock的简单示例,然后提供一个使用pthread_spinlock_t的替代方案。

使用OSSpinLock(已弃用,不推荐使用)

 

Objective-C

复制代码

1

#import <libkern/OSSpinLock.h>

2

3

OSSpinLock lock = OS_SPINLOCK_INIT;

4

5

void criticalSection() {

6

OSSpinLockLock(&lock);

7

// 临界区代码

8

OSSpinLockUnlock(&lock);

9

}

使用pthread_spinlock_t(推荐方法)

 

Objective-C

复制代码

1

#include <pthread.h>

2

3

pthread_spinlock_t spinlock;

4

5

// 初始化自旋锁

6

pthread_spin_init(&spinlock, PTHREAD_PROCESS_PRIVATE);

7

8

void criticalSection() {

9

pthread_spin_lock(&spinlock);

10

// 临界区代码

11

pthread_spin_unlock(&spinlock);

12

}

13

14

// 在不再需要锁时销毁它

15

pthread_spin_destroy(&spinlock);

在这个例子中,pthread_spinlock_t是POSIX线程库提供的自旋锁类型。使用pthread_spin_init函数初始化锁,并设置其为PTHREAD_PROCESS_PRIVATE,这意味着锁只能在同一进程的线程之间共享。在临界区前后分别调用pthread_spin_lockpthread_spin_unlock函数来加锁和解锁。最后,当锁不再需要时,应调用pthread_spin_destroy来销毁锁。

使用std::atomic_flag实现自旋锁(C++11及更高版本)

如果你在使用C++,并且你的编译器支持C++11或更高版本,你还可以使用std::atomic_flag来实现一个简单的自旋锁:

 

C++

复制代码

1

#include <

<think>嗯,用户现在想在iOS设备上获取UUID。我需要根据提供的引用内容来给出正确的指导。首先,我需要确认UUID是什么,以及iOS中获取它的方法。不过根据引用内容,有几个不同的方法。 引用1提到使用AdSupport框架的advertisingIdentifier,这会生成一个广告标识符。但需要注意,这个ID在用户重置广告标识符时会改变,而且用户可能限制广告跟踪,所以可能不是最可靠的唯一标识符。 引用3中的方法二使用了UIDevice的uniqueIdentifier,但根据我的知识,这个方法已经被苹果废弃了,现在使用会导致应用被拒绝,所以不能推荐这个方法。 引用2中的方法是通过Cocos Creator调用Objective-C的类方法,使用jsb.reflection.callStaticMethod来获取UUID。这需要用户自己实现一个DeviceHelper类,其中包含获取UUID的方法。但具体的实现方式需要用户编写原生代码,比如使用Keychain来存储和获取UUID,这样可以保证即使应用被删除后重新安装也能得到相同的UUID。 另外,用户可能需要的是设备的唯一标识符,而iOS系统现在对隐私保护很严格,不允许获取硬件级别的UUID。所以推荐的方法是生成一个UUID并存储在钥匙串中,这样即使应用删除再安装,也能保持相同。不过需要确保钥匙串的访问权限设置正确,比如使用kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly,这样即使设备重启后未解也能访问。 用户可能希望有具体的代码示例,所以需要分别给出Swift和Objective-C的实现方式。同时要提醒用户使用Keychain来持久化存储UUID,而不是每次生成新的。此外,还要注意App Store的审核指南,确保不违反隐私政策,比如不能使用广告标识符作为UUID,除非用途符合广告跟踪。 最后,用户可能需要知道在Cocos等跨平台引擎中如何集成原生代码,比如引用2中的例子,需要用户创建对应的Objective-C类,并在JavaScript中调用。这需要配置正确的类和方法名,并确保项目设置正确,比如引入必要的框架和头文件。 总结一下,正确的步骤应该是生成UUID并存储到Keychain,每次启动时尝试读取,如果没有则生成新的并保存。同时避免使用已被废弃的方法,如uniqueIdentifier,也不依赖可能变化的广告ID。</think>在iOS开发中获取设备唯一标识需遵循苹果隐私政策,推荐使用系统生成的UUID并通过Keychain持久化存储。以下是具体实现方法: ### 一、原生Swift实现方案 ```swift import Security func getDeviceUUID() -> String { let service = "com.yourcompany.app" let account = "deviceUUID" // 尝试从钥匙串读取 let query: [CFString: Any] = [ kSecClass: kSecClassGenericPassword, kSecAttrService: service, kSecAttrAccount: account, kSecReturnData: true, kSecMatchLimit: kSecMatchLimitOne ] var result: AnyObject? let status = SecItemCopyMatching(query as CFDictionary, &result) if status == errSecSuccess, let data = result as? Data, let uuid = String(data: data, encoding: .utf8) { return uuid } else { // 生成新UUID并存储 let newUUID = UUID().uuidString let data = newUUID.data(using: .utf8)! let addQuery: [CFString: Any] = [ kSecClass: kSecClassGenericPassword, kSecAttrService: service, kSecAttrAccount: account, kSecValueData: data, kSecAttrAccessible: kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly ] SecItemAdd(addQuery as CFDictionary, nil) return newUUID } } ``` ### 二、Objective-C实现方案 ```objective-c #import <Security/Security.h> - (NSString *)getPersistentUUID { NSString *service = @"com.yourcompany.app"; NSString *account = @"deviceUUID"; NSDictionary *query = @{ (__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword, (__bridge id)kSecAttrService: service, (__bridge id)kSecAttrAccount: account, (__bridge id)kSecReturnData: @YES, (__bridge id)kSecMatchLimit: (__bridge id)kSecMatchLimitOne }; CFTypeRef result = NULL; OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, &result); if (status == errSecSuccess) { NSData *data = (__bridge_transfer NSData *)result; return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; } else { NSString *newUUID = [[NSUUID UUID] UUIDString]; NSData *data = [newUUID dataUsingEncoding:NSUTF8StringEncoding]; NSDictionary *addQuery = @{ (__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword, (__bridge id)kSecAttrService: service, (__bridge id)kSecAttrAccount: account, (__bridge id)kSecValueData: data, (__bridge id)kSecAttrAccessible: (__bridge id)kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly }; SecItemAdd((__bridge CFDictionaryRef)addQuery, NULL); return newUUID; } } ``` ### 三、Cocos跨平台方案(JavaScript) 1. 创建Objective-C工具类`DeviceHelper`: ```objective-c // DeviceHelper.h #import <Foundation/Foundation.h> @interface DeviceHelper : NSObject + (NSString *)getUUID; @end // DeviceHelper.m #import "DeviceHelper.h" #import <Security/Security.h> @implementation DeviceHelper + (NSString *)getUUID { // 这里应包含上述Objective-C的钥匙串存取逻辑 // 返回持久化的UUID字符串 } @end ``` 2. 在Cocos中调用: ```javascript if (cc.sys.isNative && cc.sys.os === cc.sys.OS_IOS) { const uuid = jsb.reflection.callStaticMethod( 'DeviceHelper', 'getUUID' ); cc.log('Persistent UUID:', uuid); } ``` **注意要点**: 1. 钥匙串存储需要开启Keychain Sharing能力 2. 不要使用`[[ASIdentifierManager sharedManager] advertisingIdentifier]`,广告标识符受用户限制[^1] 3. 废弃的`uniqueIdentifier`方法会导致应用审核被拒[^3] 4. 钥匙串存储需设置`kSecAttrAccessible`属性保证数据持久性
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值