Weitere ähnliche Inhalte Ähnlich wie Objective-C atomicity #idevjp (10) Mehr von Tomohiro Kumagai (20) Kürzlich hochgeladen (12) Objective-C atomicity #idevjp4. はじまり
1. nonatomic ってなんだろう
2. なぜ今頃 atomic の話題なのか
3. @property (atomic)って何をしてくれるの?
4. 値が壊れる?
5. スレッドセーフを考慮する
1. nonatomic ってなんだろう
2. なぜ今頃 atomic の話題なのか
3. @property (atomic)って何をしてくれるの?
4. 値が壊れる?
5. スレッドセーフを考慮する
⽬目次⽬目次
6. nonatomic と⾔言えば
1. プロパティ定義で使うキーワード
2. atomic と nonatomic とがある
3. 省省略略時は atomic になる
1. プロパティ定義で使うキーワード
2. atomic と nonatomic とがある
3. 省省略略時は atomic になる
そのプロパティが原⼦子性を
保証するかを⽰示すキーワード
そのプロパティが原⼦子性を
保証するかを⽰示すキーワード
11. それは無計画さが招いた課題
1. EXC_̲BAD_̲ACCESS で落落ちる
2. 計算中に結果を取得される
3. 状態に基づく処理理中に状態が変わる
1. EXC_̲BAD_̲ACCESS で落落ちる
2. 計算中に結果を取得される
3. 状態に基づく処理理中に状態が変わる
⾃自作アプリの複数スレッドを跨ぐ処理理が
いよいよ制御しきれなくなったため!
⾃自作アプリの複数スレッドを跨ぐ処理理が
いよいよ制御しきれなくなったため!
スレッドセーフを考えなくてはいけないスレッドセーフを考えなくてはいけない
17. @synthesize での atomic 制御
読み書きする値が
正しいことを保証する
読み書きする値が
正しいことを保証する
1. インスタンス変数に書き込んでいる間、
他からの読み書きはブロックされる
1. インスタンス変数に書き込んでいる間、
他からの読み書きはブロックされる
プリミティブ型の場合プリミティブ型の場合
18. @synthesize での atomic 制御
値の正確性と合わせて
インスタンスの⽣生存を保証する
値の正確性と合わせて
インスタンスの⽣生存を保証する
1. インスタンス変数に書き込んでいる間、
他からの読み書きはブロックされる
2. ゲッターでは、ブロックの中でインスタ
ンスを retain して autorelease する
1. インスタンス変数に書き込んでいる間、
他からの読み書きはブロックされる
2. ゲッターでは、ブロックの中でインスタ
ンスを retain して autorelease する
オブジェクト型の場合オブジェクト型の場合
19. @synthesize での atomic 制御
@synthesize で保証されるのは
該当する ivar の整合性だけ
@synthesize で保証されるのは
該当する ivar の整合性だけ
インスタンス全体の
整合性は保証されない
インスタンス全体の
整合性は保証されない
20. オブジェクト全体の整合性を保証したいなら
A. 同時実⾏行行されたくないもの同⼠士をロック
B. クラスを Immutable で設計する
C. インスタンスを扱うスレッドを統⼀一する
A. 同時実⾏行行されたくないもの同⼠士をロック
B. クラスを Immutable で設計する
C. インスタンスを扱うスレッドを統⼀一する
メソッドでの処理理も考慮した
インスタンス全体の整合性を保つ制御が必要
メソッドでの処理理も考慮した
インスタンス全体の整合性を保つ制御が必要
こういったことに配慮しながら
クラスを設計する必要がある
こういったことに配慮しながら
クラスを設計する必要がある
23. インスタンス
{
int _̲a;
int _̲b;
}
-‐‑‒ (void)setA:(int)a B:(int)b
{
_̲a = a;
_̲b = b;
}
-‐‑‒ (int)total
{
return _̲a + _̲b;
}
{
int _̲a;
int _̲b;
}
-‐‑‒ (void)setA:(int)a B:(int)b
{
_̲a = a;
_̲b = b;
}
-‐‑‒ (int)total
{
return _̲a + _̲b;
}
クラス全体の整合性破壊
スレッド 1
スレッド 2
[obj setA:3 B:5];[obj setA:3 B:5];
6
[obj setA:1 B:3];[obj setA:1 B:3];
[obj total];[obj total];a ⇦ 1
[3]
b ⇦
3
[5]
4
a ⇦ 3
[1]
b ⇦
5
[2]
8
⏎ 1
+ 5
[4]
?
25. インスタンス
{
long long _̲val;
}
-‐‑‒ (void)setVal:(long long)val
{
_̲val = val;
}
-‐‑‒ (long long)val
{
return _̲val;
}
{
long long _̲val;
}
-‐‑‒ (void)setVal:(long long)val
{
_̲val = val;
}
-‐‑‒ (long long)val
{
return _̲val;
}
プロパティの整合性破壊?
スレッド 1
スレッド 2
obj.val = 1;obj.val = 1;
4294967295
1
-‐‑‒1
obj.val = -‐‑‒1obj.val = -‐‑‒1
obj.val;obj.val;
!?_̲val ⇦ -‐‑‒1
[2]
_̲val ⇦ 1
[1]
⏎ -‐‑‒1[3]
27. インスタンス
{
long long _̲val;
}
-‐‑‒ (void)setVal:(long long)val
{
_̲val = val;
}
-‐‑‒ (long long)val
{
return _̲val;
}
{
long long _̲val;
}
-‐‑‒ (void)setVal:(long long)val
{
_̲val = val;
}
-‐‑‒ (long long)val
{
return _̲val;
}
プロパティの整合性破壊!
スレッド 1
スレッド 2
obj.val = 1;obj.val = 1;
4294967295
obj.val = -‐‑‒1obj.val = -‐‑‒1
obj.val;obj.val;
下位ビット
[3]
上位
ビット
[6]
-‐‑‒1
下位ビット
[1]
上位
ビット
[2]
1
下位ビット
[4]
上位
ビット
[5]
!
30. インスタンス
@interface MyClass
{
NSString* _̲string;
}
@property (nonatomic,readwrite,rcopy) NSString* string;
@end
@implementation MyClass
@synthesize string = _̲string;
@end
@interface MyClass
{
NSString* _̲string;
}
@property (nonatomic,readwrite,rcopy) NSString* string;
@end
@implementation MyClass
@synthesize string = _̲string;
@end
インスタンスの予期しない解放
スレッド 1
スレッド 2
string = [obj.string retain];string = [obj.string retain];
[string retain]
[3]
Bad Access !
⏎
_̲string
[1]
[_̲string
release]
[2]
_̲string =
[ssss copy]
[4]
obj.string = ssss;obj.string = ssss;
36. ブロックの⽅方法
Objective-‐‑‒C で使えるロックの紹介Objective-‐‑‒C で使えるロックの紹介
a) @synchronized (self)
― 続くブロック {} を再帰ロック
― 指定したインスタンスがキーになる
b) NSRecursiveLock
― -‐‑‒lock から -‐‑‒unlock までを再帰ロック
― pthread_̲mutex の Objective-‐‑‒C 版
c) セマフォ
― dispatch_̲semaphore でロック
― タイムアウトの指定も可能
a) @synchronized (self)
― 続くブロック {} を再帰ロック
― 指定したインスタンスがキーになる
b) NSRecursiveLock
― -‐‑‒lock から -‐‑‒unlock までを再帰ロック
― pthread_̲mutex の Objective-‐‑‒C 版
c) セマフォ
― dispatch_̲semaphore でロック
― タイムアウトの指定も可能
38. 読み書きでの値の破壊を防ぐ
プリミティブ型の @property (atomic) を
@synthesize したときに採られる⽅方法
プリミティブ型の @property (atomic) を
@synthesize したときに採られる⽅方法
1. セッターとゲッターを
同じキーでロックする
1. セッターとゲッターを
同じキーでロックする
同時アクセスを防ぎ
値の⽭矛盾を起こさない
同時アクセスを防ぎ
値の⽭矛盾を起こさない
39. インスタンス
@interface MyObject : NSObject
{
long long _̲val;
}
@property (atomic,readwrite) long long val;
@end
@implementation MyObject
@synthesize val = _̲val;
@end
@interface MyObject : NSObject
{
long long _̲val;
}
@property (atomic,readwrite) long long val;
@end
@implementation MyObject
@synthesize val = _̲val;
@end
atomic キーワードを使⽤用する
スレッド 1
スレッド 2
obj.val = 1;obj.val = 1;
-‐‑‒1
obj.val = -‐‑‒1obj.val = -‐‑‒1
obj.val;obj.val;
下位ビット
[2]
上位
ビット
[2]
-‐‑‒1
下位ビット
[1]
上位
ビット
[1]
1
下位ビット
[3]
上位
ビット
[3]
Lock!Lock!
Lock!Lock!
Lock!Lock!
OK
!
40. 内部的な実装は次のような感じに
@synthesize で⽣生成される内部ロックは
@synchronized (self) とはまったく別のもの
@synthesize で⽣生成される内部ロックは
@synchronized (self) とはまったく別のもの
Setter
-‐‑‒ (void)setVal:(long long)val
{
[_̲lock lock];
_̲val = val;
[_̲lock unlock];
}
-‐‑‒ (void)setVal:(long long)val
{
[_̲lock lock];
_̲val = val;
[_̲lock unlock];
}
Getter
-‐‑‒ (long long)val
{
[_̲lock lock];
@try
{
return _̲val;
}
@finally
{
[_̲lock unlock];
}
}
-‐‑‒ (long long)val
{
[_̲lock lock];
@try
{
return _̲val;
}
@finally
{
[_̲lock unlock];
}
}
42. インスタンスを確実に retain する
1. セッターとゲッターを
同じキーでロックする
2. ゲッターのロック内でインスタンス
を retain & autorelease する
1. セッターとゲッターを
同じキーでロックする
2. ゲッターのロック内でインスタンス
を retain & autorelease する
インスタンスを確実に確保して
呼び出し元が正しく受け取れるようにする
インスタンスを確実に確保して
呼び出し元が正しく受け取れるようにする
オブジェクト型の @property (atomic) を
@synthesize したときに採られる⽅方法
オブジェクト型の @property (atomic) を
@synthesize したときに採られる⽅方法
43. インスタンス
@interface MyClass
{
NSString* _̲string;
}
@property (atomic,readwrite,copy) NSString* string;
@end
@implementation MyClass
@synthesize string = _̲string;
@end
@interface MyClass
{
NSString* _̲string;
}
@property (atomic,readwrite,copy) NSString* string;
@end
@implementation MyClass
@synthesize string = _̲string;
@end
インスタンスを確実に retain する
スレッド 1
スレッド 2
string = [obj.string retain];string = [obj.string retain];
[_̲string
release]
[2]
_̲string =
[ssss retain]
[2]
obj.string = ssss;obj.string = ssss;
[string retain]
[3]
[_̲string
retain]
[1]
[_̲string
autorelease]
[1]
⏎ _̲string[1]
Lock!Lock!
Lock!Lock!
KEEP!
OK
!
44. 内部的な実装は次のような感じに
親インスタンスの dealloc で _̲string が
解放されるところまでは保護されない
親インスタンスの dealloc で _̲string が
解放されるところまでは保護されない
Setter
-‐‑‒ (void)setString:
(NSString*)string
{
[_̲lock lock];
_̲string = [string copy];
[_̲lock unlock];
}
-‐‑‒ (void)setString:
(NSString*)string
{
[_̲lock lock];
_̲string = [string copy];
[_̲lock unlock];
}
Getter
-‐‑‒ (NSString*)string
{
[_̲lock lock];
@try
{
[_̲string retain];
[_̲string autorelease];
return _̲string;
}
@finally
{
[_̲lock unlock];
}
}
-‐‑‒ (NSString*)string
{
[_̲lock lock];
@try
{
[_̲string retain];
[_̲string autorelease];
return _̲string;
}
@finally
{
[_̲lock unlock];
}
}
47. インスタンス
-‐‑‒ (void)setA:(int)a B:(int)b
{
@synchronized (self)
{
_̲a = a;
_̲b = b;
}
}
-‐‑‒ (int)total
{
@synchronized (self)
{
return _̲a + _̲b;
}
}
-‐‑‒ (void)setA:(int)a B:(int)b
{
@synchronized (self)
{
_̲a = a;
_̲b = b;
}
}
-‐‑‒ (int)total
{
@synchronized (self)
{
return _̲a + _̲b;
}
}
整合性に関係する範囲をロックする
スレッド 1
スレッド 2
[obj setA:3 B:5];[obj setA:3 B:5];
4
[obj setA:1 B:3];[obj setA:1 B:3];
[obj total];[obj total];
a ⇦ 1
[2]
b ⇦
3
[2]
4
a ⇦ 3
[1]
b ⇦
5
[1]
8
⏎ 1
+ 3
[3]
Lock!Lock!
Lock!Lock!
Lock!Lock!
OK
!
50. インスタンス
@interface MyClass
{
NSString* _̲string;
}
@property (nonatomic,readwrite,copy) NSString* string;
@end
@implementation MyClass
@synthesize string = _̲string;
@end
@interface MyClass
{
NSString* _̲string;
}
@property (nonatomic,readwrite,copy) NSString* string;
@end
@implementation MyClass
@synthesize string = _̲string;
@end
実⾏行行するスレッドをひとつに統⼀一する
スレッド 1
スレッド 2
string = [obj.string retain];string = [obj.string retain];
[string retain]
[2]
[_̲string
release]
[3]
_̲string =
[ssss copy]
[4]
[obj performSelector:@selector(setString:)
onThread:スレッド2
withObject:ssss
waitUntilDone:NO];
[obj performSelector:@selector(setString:)
onThread:スレッド2
withObject:ssss
waitUntilDone:NO];
No Lock.No Lock.
⏎
_̲string
[1]
OK
!
54. クラスを Immutable で設計する
値は init メソッドで設定して
インスタンス⽣生成後は値の取得だけができる
値は init メソッドで設定して
インスタンス⽣生成後は値の取得だけができる
クラス定義
@interface MyClass : NSObject
@property (nonatomic,readonly) long long a;
@property (nonatomic,readonly) long long b;
@property (nonatomic,readonly) long long total;
-‐‑‒ (id)initWithA:(long long)a B:(long long)b;
@end
@interface MyClass : NSObject
@property (nonatomic,readonly) long long a;
@property (nonatomic,readonly) long long b;
@property (nonatomic,readonly) long long total;
-‐‑‒ (id)initWithA:(long long)a B:(long long)b;
@end
55. クラスを Immutable で設計する
クラス実装
@implementation MyClass
-‐‑‒ (id)initWithA:(long long)a B:(long long)b
{
self = [super init];
if (self)
{
_̲a = a;
_̲b = b;
}
return self;
}
-‐‑‒ (long long)total
{
return _̲a + _̲b;
}
@implementation MyClass
-‐‑‒ (id)initWithA:(long long)a B:(long long)b
{
self = [super init];
if (self)
{
_̲a = a;
_̲b = b;
}
return self;
}
-‐‑‒ (long long)total
{
return _̲a + _̲b;
}
56. インスタンス
@interface TestClass
{
MyClass* _̲obj;
}
@property (atomic,readwrite,retain) MyClass* obj;
@end
@implementation MyClass
@synthesize obj = _̲obj;
@end
@interface TestClass
{
MyClass* _̲obj;
}
@property (atomic,readwrite,retain) MyClass* obj;
@end
@implementation MyClass
@synthesize obj = _̲obj;
@end
クラスを Immutable で設計する
スレッド 1
スレッド 2
test.obj = [[MyClass alloc] initWithA:3 B:5];test.obj = [[MyClass alloc] initWithA:3 B:5];
4
test.obj = [[MyClass alloc] initWithA:1 B:3];test.obj = [[MyClass alloc] initWithA:1 B:3];
[test.obj total];[test.obj total];
_̲obj =
[obj retain]
[2]4
_̲obj =
[obj retain]
[1]8
[_̲obj
retain]
[3]
[_̲obj
autorelease]
[3]
⏎ _̲obj[3]
Lock!Lock!
[test.obj total]
[2]
Lock!Lock!
Lock!Lock!
OK
!
59. 2.予期しない値の変化を防ぐ
渡された NSString を
複製してインスタンス変数に持つ⽅方法
渡された NSString を
複製してインスタンス変数に持つ⽅方法
複製を内部に持つ事で
外部での値変更更の影響を受けない
複製を内部に持つ事で
外部での値変更更の影響を受けない
1. NSString のインスタンスは編集可能な
場合がある (NSMutableString)
2. そこで copy して、渡されたものとは
別の NSString を持つようにする
1. NSString のインスタンスは編集可能な
場合がある (NSMutableString)
2. そこで copy して、渡されたものとは
別の NSString を持つようにする