2012年1月11日 星期三

iOS - Thread - NSOperation


目的
  • 使用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

沒有留言:

張貼留言