2013-02-10 2 views
2

NSView를 렌더링하고 다른 곳에서 사용할 이미지로 HTTP 인터페이스를 통해 반환하는 Mac OS X 서버 응용 프로그램이 있습니다. 눈에 보이는 UI는 없으며 애플리케이션은 NSWindow없이 분리 된 NSView를 만듭니다.코코아의 다중 UI 스레드

응용 프로그램은 한 번에 많은 요청을받을 수 있지만 레이아웃 및 렌더링 프로세스는 코코아 UI가 스레드 안전하지 않으므로 주 스레드 (GCD의 dispatch_sync 사용)에서 동기화되므로 한 번에 하나의 요청으로 처리량이 감소합니다 그 코드 부분.

각 요청은 아무것도 공유하지 않고 완전히 분리되어 있기 때문에 코코아 애플리케이션이 여러 개의 완전히 다른 UI 스레드를 효과적으로 실행하는 방법이 있습니까? 아마도 다중 실행 루프를 사용하고 있을까요?

가능한 경우 여러 프로세스를 실행하지 않아야합니다.

+1

여기에 더 자세한 내용이 필요하다고 생각합니다. NSView를 렌더링한다고합니다. 어떻게 이러는거야? (즉, 수동으로'-drawRect :'를 호출하고 있습니까?)보기에 무엇이 있습니까? – ipmcc

+0

Snow Leopard 이후 백그라운드 스레드 (NSView canDrawConcurrently)에서 동시 드로잉을위한 일반적인 흐름 (즉, 실제로 제공된 UI에 참여하는 NSView)에서 지원이 있습니다. 그게 당신이하고있는 것입니다. 왜냐하면 뷰는 윈도우의 뷰 계층과 관련이 없기 때문입니다. 그러나 다시 ... 우리는 더 자세한 정보가 필요합니다. – ipmcc

+0

예 .. 드로잉은 동시에 발생할 수 있지만 대부분의 API는 '스레드 안전'이 아닙니다. –

답변

1

귀하의 특정 요구 사항에 따라 확실하게 말할 수는 없지만 (귀하의 특정 요구 사항에 귀하의 질문에서 메인 스레드 의존성이 표시되지 않을 수 있기 때문에) 특히 여기서 논란이되는 내용은 없습니다. 예를 들어, 다음 코드는 문제없이 잘 작동 : 여기

CGImageRef CreateImageFromView(NSView* view) 
{ 
    const CGSize contextSize = CGSizeMake(ceil(view.frame.size.width), ceil(view.frame.size.height)); 
    const size_t width = contextSize.width; 
    const size_t height = contextSize.height; 
    const size_t bytesPerPixel = 32; 
    const size_t bitmapBytesPerRow = 64 * ((width * bytesPerPixel + 63)/64); // Alignment 
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 
    CGContextRef context = CGBitmapContextCreate(NULL, width, height, 8, bitmapBytesPerRow, colorSpace, kCGBitmapByteOrder32Host | kCGImageAlphaPremultipliedLast); 
    CGColorSpaceRelease(colorSpace); 
    [view displayRectIgnoringOpacity: view.bounds inContext: [NSGraphicsContext graphicsContextWithGraphicsPort: context flipped: YES]]; 
    CGImageRef image = CGBitmapContextCreateImage(context); 
    CGContextRelease(context); 
    return image; 
} 

- (IBAction)doStuff:(id)sender 
{ 
    static NSUInteger count = 0; 

    for (NSUInteger i =0; i < 100; ++i) 
    { 
     dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 
      NSButton* button = [[[NSButton alloc] initWithFrame: NSMakeRect(0, 0, 200, 100)] autorelease]; 
      button.title = [NSString stringWithFormat: @"Done Stuff %lu Times", (unsigned long)count++]; 
      CGImageRef image = CreateImageFromView(button); 
      NSImage* nsImage = [[[NSImage alloc] initWithCGImage:image size: NSMakeSize(CGImageGetWidth(image), CGImageGetHeight(image))] autorelease]; 
      CGImageRelease(image); 
      dispatch_async(dispatch_get_main_queue(), ^{ 
       self.imageView.image = nsImage; 
      }); 
     }); 
    } 
} 

의 핵심은 모든 배경 렌더링 작업에 "개인"이 될 것입니다. 자체보기, 자체 그래픽 컨텍스트 등을 얻습니다. 아무 것도 공유하지 않으면이 작업이 정상적으로 이루어집니다. 귀하가 명시 적으로 말했듯이, "각 요청이 완전히 분리되어 있고 그들 사이에 아무 것도 공유되지 않은 상태에서"귀하는 이미이 조건을 만족 시켰다고 생각합니다.

사용해보기. 문제가 생기면 의견을 남기십시오.

+0

감사합니다 ipmcc,이 올바른 경로에 나를 설정합니다. 이전에 테스트를 진행하면서 실수로 같은 문서에서 여러 페이지를 동시에 래스터 화하려고 시도하여 일반적인 Core Text 객체에 문제가 발생했습니다. 각 페이지를 문서 당 직렬 디스패치 대기열에 넣고 서로 밟지 않고 여러 문서를 동시에 처리 할 수 ​​있습니다. 또 다른, 아마도 관련 버그, 내가 불필요하게 공유 NSGraphicsContext 스택을 저장하고 복원했다. 독립 NSGraphicsContext를 만들므로 주 스택에는 영향을 미치지 않습니다. – tomtaylor

+0

문서가 변경되지 않는다고 가정하면 CoreText 객체의 비공개 사본을 만들어 동일한 문서 내에서 작업을 병렬 처리 할 수도 있습니다. – ipmcc

+0

좋은 지적, 감사합니다. – tomtaylor