目的
- 使用NSOperationQueue達成執行緒實作
工具
- NSOperation
- NSOperationQueue
- 執行緒池,將NSOperation放入交由系統執行
- NSCondition
- 類似JAVA中的synchronized機制,使用"lock" & "unlock"防止多執行緒同時存取相同的變數
使用範例
﹣實現Producer & Consumer
Store.h
// Store用來管理Producer及Consumer一同存取的容器
// 故需要考慮到同步的問題,不可發生同時存取相同容器的問題
@interface Store : NSObject
{
NSMutableArray* mProducts; NSCondition* mLocker;
}
- (id) initStore;
- (void) add:(NSNumber*) product;
- (NSNumber*) get;
@end
Store.m
#import "Store.h"
@implementation Store
- (id) initStore
{
self = [super init];
if (self){
mProducts = [[NSMutableArray alloc] init];
mLocker = [[NSCondition alloc] init];
}
return self;
}
- (void) add:(NSNumber*) product
{
// 同步add product階段
[mLocker lock];
while ([mProducts count] >= 2)
{
[mLocker wait];
}
[mProducts addObject:product];
[mLocker signal];
// wake up one thread
[mLocker unlock];
}
- (NSNumber*) get
{
// 同步get product階段
[mLocker lock];
while ([mProducts count] <= 0)
{
[mLocker wait];
NSNumber* product = [mProducts objectAtIndex:0];
[mProducts removeObjectAtIndex:0];
[mLocker signal];
// wake up one thread
[mLocker unlock]; return product;
}
@end
Producer.h
// 將數字放入容器中 #import "Store.h"
@interface Producer : NSOperation
{
Store* mStore;
}
- (id) initProducer:(Store*) store;
- (void) main;
@end
Producer.m
#import "Producer.h"
@implementation Producer
- (id) initProducer:(Store*) store
{
self = [super init];
if (self) {
mStore = store;
}
return self;
}
- (void) main
{
for (int iProduct = 1; iProduct <= 10; iProduct++)
{
// 隨機睡眠 0~4秒
[NSThread sleepForTimeInterval:(arc4random() % 5)];
[mStore add:[NSNumber numberWithInt:iProduct]];
NSLog(@"Produce %d", iProduct);
}
}
@end
Consumer.h
// 將收字從容器中拿出 #import "Store.h"
@interface Consumer : NSOperation
{
Store* mSotre;
}
- (id) initConsumer:(Store*) store;
- (void) main;
@end
Consumer.m
#import "Consumer.h"
@implementation Consumer
- (id) initConsumer:(Store*) store
{
self = [super init];
if (self)
{
mSotre = store;
}
return self;
}
- (void) main
{
for (int iLoop = 0; iLoop <= 10; iLoop++)
{
[NSThread sleepForTimeInterval:(arc4random() % 5)];
NSLog(@"Consume %d", [[mSotre get] intValue]);
}
}
@end
ViewController.h
#import "Producer.h"
#import "Consumer.h"
#import "Store.h"
@interface ViewController : UIViewController
{
NSOperationQueue* mQueue;
Producer* mProducer;
Consumer* mConsumer;
Store* mStore;
}
@end
ViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
mQueue = [[NSOperationQueue alloc] init];
mStore = [[Store alloc] initStore];
// 將Store放入Producer & Consumer裡
mProducer = [[Producer alloc] initProducer:mStore];
mConsumer = [[Consumer alloc] initConsumer:mStore];
// 將Producer & Consumer放入Operation queue中,
// 開始執行Producer & Consumer
[mQueue addOperation:mProducer];
[mQueue addOperation:mConsumer];
}
Note
- 其中"[mLocker signal];" 可代換成"[mLocker broadcast];",差別在於前者"signal"喚醒一個等待此thread的thread;而後者喚醒所有在等待此thread的thread