외규장각 도서 환수 모금 캠페인
BLOG main image
분류 전체보기 (45)
컴퓨팅환경 (18)
프로그래밍 (18)
놀이 (2)
잡담 (7)
«   2010/03   »
  1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31      
10,199 Visitors up to today!
Today 0 hit, Yesterday 28 hit
daisy rss
meet me at me2DAY
나눔글꼴 내려받기
tistory
2008/12/31 17:59

Mac OS X 10.5부터 NSOperationQueue를 이용하여 Thread Pool 기반의 Worker Thread Model을 아주 쉽게 만들 수 있게 되었다. 이것은 priority, dependency까지 설정할 수 있기 때문에 범용으로 사용할 수 있을 뿐 아니라 인터페이스도 매우 쉽게 되어 있다.

내가 필요한 것은 백그라운드 쓰레드 하나가 그냥 기다리고 있다가 특정 메소드 호출만 처리해 주는 단순한 것인데, NSOperationQueue는 좀 뒤뚱한 짓을 하고 있었다. MaxConcurrentOperationCount를 1로 주었는데, 내부적으로 쓰레드풀을 관리한답시고 고작 쓰레드 하나를 만들었다가 없앴다가 반복하는 등...

하지만, 제대로 만들기 위해 메세지큐 만들고, condition lock하고 signal 보내고... 싫었다. 그래서, NSRunLoop을 이용해서 정말 간단하게 하나 만들어 보았다.

#import <Foundation/Foundation.h>


@interface WorkerThread : NSObject
{
    NSThread *thread;
    NSLock   *lock;
}

- (void)start;
- (void)stop;

- (void)performSelector:(SEL)aSelector target:(id)target withObject:(id)anObject;

@end

@implementation WorkerThread

- (id)init
{
    self = [super init];

    if (self)
    {
        thread = [[NSThread alloc] initWithTarget:self selector:@selector(main) object:nil];
        lock   = [[NSLock alloc] init];
    }

    return self;
}

- (void)dealloc
{
    [thread release];
    [lock release];
    [super dealloc];
}

- (void)main
{
    NSAutoreleasePool *mainPool;
    NSAutoreleasePool *loopPool;

    mainPool = [[NSAutoreleasePool alloc] init];

    [lock lock];

    [self performSelector:@selector(self) onThread:thread withObject:nil waitUntilDone:NO];

    while (![thread isCancelled])
    {
        loopPool = [[NSAutoreleasePool alloc] init];
        [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1]];
        [loopPool release];
    }

    [lock unlock];

    [mainPool release];
}

- (void)start
{
    [thread start];
}

- (void)stop
{
    [thread cancel];

    [lock lock];
    [lock unlock];
}

- (void)performSelector:(SEL)aSelector target:(id)target withObject:(id)anObject
{
    [target performSelector:aSelector onThread:thread withObject:anObject waitUntilDone:NO];
}

@end

NSRunLoop은 input source로부터 input을 기다리게 되는데, 만약, input source가 없다면 run loop이 종료된다. 48번째 라인은 자기자신에게 self를 호출하는 의미없는 라인처럼 보이지만, 이 때 message send에 대한 input source가 등록된다.

한가지 깔끔하지 못한 것은 48번째 라인에 의해 등록된 input source를 해제할 방법이 없다는 것이다. 그렇기 때문에, 플래그로 1초마다 쓰레드를 종료해야할 지 말지 결정한다. 만약, 이 쓰레드가 프로그램이 종료할 때까지 멈출 필요가 없다면 while문을 없애고 다음과 같이 바꿔도 무방하다.

[[NSRunLoop currentRunLoop] run];

 

이 글은 스프링노트에서 작성되었습니다.