2012-11-23 3 views
2

@synchronized 지시문이 어떻게 작동하는지 보려면이 멀티 스레딩 응용 프로그램을 수행하고 있습니다. 모든 스레드가 @synchronized의 인수와 동일한 객체를 갖고 있으면 모두 동일하게 기다립니다. 자물쇠. 그래서 나는 모든 스레드에 대해 동일하기 때문에 자기를 인수로 사용한다고 생각했다.
이 응용 프로그램에는 모든 스레드가 여러 번 편집하는 텍스트 필드가 있습니다. 퍼포먼스는 신경 쓰지 않아요. 테스트를위한 것이기 때문에, 전에는 @synchronized 지시어를 쓰지 않고 안에 넣으십시오. 내가 사용하는단순 멀티 스레딩 응용 프로그램이 때때로 실패합니다.

속성 :

@property (weak) IBOutlet NSTextField *textField; 
@property (nonatomic, copy) NSNumber* value; 
@property (nonatomic,copy) NSMutableArray* threads; 

코드 :

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification 
{ 
    value= @0; 
    textField.objectValue= value; 
    for(int i=0; i<10; i++) 
    { 
     NSThread* thread=[[NSThread alloc]initWithTarget: self selector: @selector(routine:) object: nil]; 
     [threads addObject: thread]; 
     [thread start]; 
    } 
} 

- (void) routine : (id) argument 
{ 
    for(NSUInteger i=0; i<100; i++) 
    { 
     @synchronized(self) 
     { 
      value= @(value.intValue+1); 
      textField.objectValue= value; 
     } 
    } 
} 

때로는 응용 프로그램이 성공을 가지고 있으며, 나는이 것을 두려워, 때로는 텍스트가 아닌 필드 value.But로 1000 참조 기아와 텍스트 필드에 아무것도 표시되지 않습니다, 그것은 비어 있습니다. 나는 디버그를 시도하지만, 오류의 기준이 나에게 캐주얼 것 때문에 잘못 본 것이 어렵다 때로는 그냥 잘 작동합니다.

SOLUTION

@synthesize threads,value, textField; 

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification 
{ 
    value= @0; 
    threads=[[NSMutableArray alloc]initWithCapacity: 100]; 
    for(NSUInteger i=0; i<100; i++) 
    { 
     NSThread* thread=[[NSThread alloc]initWithTarget: self selector: @selector(routine:) object: nil ]; 
     [threads addObject: thread]; 
     [thread start]; 
    } 
} 

- (void) routine : (id) arg 
{ 
    for(NSUInteger i=0; i<1000; i++) 
    { 
     @synchronized(self) 
     { 
      value= @(value.intValue+1); 
      [textField performSelectorOnMainThread: @selector(setObjectValue:) withObject: value waitUntilDone: NO]; 
     } 
    } 
} 
+1

이것이 가능합니까? 나는 좋은 질문을 찾았다. 아니면 그냥 꿈꿔? (+1 재미있는 문제입니다.) –

+1

모르겠다 .. 내게 괜찮아 보이는 코드 ..하지만 appkit의 어느 부분이 스레드 안전하다고 확신하지 않습니다 ... –

+1

추가 된 솔루션이 올바르지 않습니다. [알림은 같은 스레드에서 게시 및 수신됩니다.] (http://stackoverflow.com/questions/1004589/nsnotificationcenter-do-objects-receive-notifications-on-the-same-thread-they-a) 중단 점 설정 '-changeValue :'에서 현재 스레드가 주 스레드가 아님을 알 수 있습니다. –

답변

3

가 아닌 메인 쓰레드에서 NSView의 서브 클래스 인 NSTextField를 액세스한다. That is not a safe thing to do. 결과는 정의되지 않습니다. 때로는 효과가있는 것처럼 보이기도하고 때로는 그렇지 않은 경우도 있습니다.

+0

대체 솔루션은 무엇입니까?어떻게 든 메시지를 보내서 주 스레드를 호출하여 선택기를 실행하게해야합니까? –

+1

예,'- [NSObject performSelectorOnMainThread : withObject : waitUntilDone :]'또는 GCD를 사용하여 주 스레드에서 코드를 실행하십시오. [예제가 있습니다.] (http://stackoverflow.com/questions/7290931/gcd-threads-program-flow-and-ui-updating/7291056#7291056) "NSView thread update"와 같은 것을 검색하면 더 많은 예제들. –

+1

메모 :'[NSNotificationCenter defaultCenter]'에 알림을 게시하는 것은 * 메인 스레드에 접근하는 것이 아닙니다. 알림 옵저버는 알림 게시와 동일한 스레드에서 동시에 호출됩니다. –

1

항상 백그라운드 스레드에서 UI를 업데이트하고 있습니다. 이것은 좋지 않다. 당신은 그것을해야한다;

(void)applicationDidFinishLaunching:(NSNotification *)aNotification 
{ 
    value= @0; 
    textField.objectValue= value; 
    for(int i=0; i<10; i++) 
    { 
     NSThread* thread=[[NSThread alloc] initWithTarget: self selector: @selector(routine:) object: nil]; 
     [threads addObject: thread]; 
     [thread start]; 
    } 
} 

- (void) routine : (id) argument 
{ 
    for(NSUInteger i=0; i<100; i++) 
    { 
     @synchronized(self) 
     { 
      value= @(value.intValue+1); 
      [textField performSelectorOnMainThread:@selector(setObjectValue:) withObject:value waitUntilDone: NO];  
     } 
    } 
} 

인스턴스를 잠그고 잠자기 방법을 사용하면 더 부드럽게 만들 수 있습니다.

변수를 백그라운드 스레드에 잠 그려면 먼저 변수를 잠근 다음 값을 설정하고 다음과 같이 잠금을 해제하십시오.

[NSLock lock]; 
[email protected](value.intValue+1) 
[NSLock unlock]; 

, 당신은 이미 동시에 여러 스레드에서 액세스 할 수있는 변수에 대한 보호하게하는 @synchronized있다. 나는 @ 싱크 블록을 이해하기가 더 쉽다고 생각한다.

이 경우에는 수면이 더 적절합니다. 스레드 안에 2 초 정도의 잠을 자면 2 초마다 textField가 변경되는 것을 볼 수 있습니다.

[NSThread sleepForTimeInterval:2000] // textField를 업데이트 한 후이 코드를 루프 안에 넣고 효과를 확인하십시오.

또한 runloop을 만들고 더 나은 방법 인 runloop에서 스레드를 실행하는 것이 좋습니다.