객체를 생성한 스레드에서 명시적으로 액세스하지 않는 경우 스레드 외부에서 생성한 객체를 조작하는 것이 안전합니까?

StackOverflow https://stackoverflow.com/questions/67154

문제

저는 코코아 소프트웨어를 작업 중이며 대규모 데이터 가져오기(핵심 데이터) 중에 GUI의 응답성을 유지하려면 메인 스레드 외부에서 가져오기를 실행해야 합니다.

잠금을 사용하지 않고 메인 스레드에서 해당 객체를 생성한 경우에도 해당 객체에 액세스하는 것이 안전합니까? 만약에 스레드가 실행되는 동안에는 해당 개체에 명시적으로 액세스하지 않습니다.

도움이 되었습니까?

해결책

Core Data를 사용하면 동일한 코디네이터 및 영구 저장소에 연결된 가져오기 스레드에 사용할 별도의 관리 객체 컨텍스트가 있어야 합니다.메인 스레드가 사용하는 컨텍스트에서 생성된 개체를 다른 스레드에 던져서 작동할 것이라고 기대할 수는 없습니다.게다가 이를 위해 사용자 스스로 잠금을 수행할 수도 없습니다.당신은 최소한 객체가 있는 관리 객체 컨텍스트를 적절하게 잠가야 합니다.그러나 해당 객체가 뷰 컨트롤에 의해 바인딩된 경우 컨텍스트 잠금을 추가할 수 있는 "후크"가 없습니다.

공짜 점심은 없습니다.

Ben Trumbull은 별도의 컨텍스트를 사용해야 하는 몇 가지 이유와 "그냥 읽는 것"이 ​​생각만큼 간단하거나 안전하지 않은 이유를 설명합니다. webobjects-dev 목록에 있는 2004년 말의 훌륭한 게시물입니다..(전체 스레드가 훌륭합니다.) 그는 Enterprise Objects Framework 및 WebObjects에 대해 논의하고 있지만 그의 조언은 핵심 데이터에도 완전히 적용 가능합니다.메시지 내용에서 "EC"를 "NSManagedObjectContext"로 바꾸고 "EOF"를 "Core Data"로 바꾸면 됩니다.

Enterprise Objects Framework와 같이 핵심 데이터의 스레드간에 데이터를 공유하는 문제에 대한 해결책은 "그렇지 않습니다"입니다. 당신이 그것에 대해 더 생각하고 당신이 실제로, 당신이 실제로, 정직하게 스레드간에 데이터를 공유해야한다면, 솔루션은 스레드 분리 컨텍스트에서 독립 객체 그래프를 유지하고 한 컨텍스트에서 저장 알림에 정보를 사용하여 다른 맥락을 다시 가져와야합니다. -[NSManagedObjectContext refreshObject:mergeChanges:] 이 사용을 지원하도록 특별히 설계되었습니다.

다른 팁

나는 이것이라고 믿는다 ~ 아니다 CoreData NSManagedObjectContext에 의해 관리되는 NSManagedObject(또는 하위 클래스)를 사용하는 것이 안전합니다.일반적으로 CoreData는 관리되는 개체의 상태에 대해 별도의 스레드에서 해당 개체와 관련된 오류를 발생시키는 것을 포함하여 많은 까다로운 작업을 수행할 수 있습니다.특히, [NSManagedObject initWithEntity:insertIntoManagedObjectContext:] (OS X 10.5부터 NSManagedObjects에 대해 지정된 초기화 프로그램)은 반환된 개체가 다른 스레드에 전달되는 것이 안전하다는 것을 보장하지 않습니다.

다중 스레드와 함께 CoreData를 사용하는 방법은 Apple's에 잘 문서화되어 있습니다. 개발 사이트.

잠금 사용의 요점은 두 스레드가 동일한 리소스에 액세스하려고 시도하지 않도록 하는 것입니다.다른 메커니즘을 통해 이를 보장할 수 있다면 그렇게 하십시오.

안전하더라도 해당 필드에 대한 액세스를 동기화하지 않고 스레드 간에 공유 데이터를 사용하는 것은 모범 사례가 아닙니다.어떤 스레드가 객체를 생성했는지는 중요하지 않지만, 두 개 이상의 실행 라인(스레드/프로세스)이 동시에 객체에 액세스하는 경우 데이터 불일치가 발생할 수 있습니다.

단 하나의 스레드만 이 개체에 액세스할 것이라고 확신하는 경우 액세스를 동기화하지 않는 것이 안전합니다.그럼에도 불구하고 나중에 애플리케이션 변경으로 인해 액세스 동기화에 대한 걱정 없이 동일한 데이터를 공유하는 두 번째 스레드가 추가될 때까지 기다리는 것보다 지금 코드에 동기화를 추가하는 것이 좋습니다.

예, 안전합니다.매우 일반적인 패턴은 개체를 만든 다음 대기열이나 다른 컬렉션에 추가하는 것입니다.두 번째 "소비자" 스레드는 대기열에서 항목을 가져와서 해당 항목으로 작업을 수행합니다.여기서는 대기열을 동기화해야 하지만 대기열에 추가된 개체는 동기화하지 않아야 합니다.

모든 것을 동기화하고 최선을 다하는 것은 좋은 생각이 아닙니다.디자인과 개체에 작용할 수 있는 스레드가 무엇인지에 대해 매우 신중하게 생각해야 합니다.

고려해야 할 두 가지 사항은 다음과 같습니다.

  • 객체가 다른 스레드에서 사용 가능해지기 전에 객체가 완전히 생성되고 초기화되었음을 보장할 수 있어야 합니다.
  • 메인(GUI) 스레드가 데이터가 로드되었고 모든 것이 정상임을 감지하는 몇 가지 메커니즘이 있어야 합니다.스레드로부터 안전하려면 필연적으로 일종의 잠금이 필요합니다.

응, 할 수 있어, 안전할 거야

...두 번째 프로그래머가 와서 당신이 만든 것과 동일한 가정을 이해하지 못할 때까지.두 번째(또는 세 번째, 네 번째, 다섯 번째, ...) 프로그래머는 생성자 스레드에서 안전하지 않은 방식으로 개체를 사용하기 시작할 가능성이 높습니다.발생하는 문제는 매우 미묘하고 추적하기 어려울 수 있습니다.그 이유만으로도 그리고 이 개체를 여러 스레드에서 사용하고 싶은 유혹이 크기 때문에 개체 스레드를 안전하게 만들겠습니다.

명확히 하자면, (댓글을 남겨주신 분들께 감사드립니다):

"스레드 안전"이란 스레딩 문제를 방지하기 위한 체계를 프로그래밍 방식으로 고안하는 것을 의미합니다.반드시 개체 주위에 잠금 체계를 고안해야 한다는 뜻은 아닙니다.작성자 스레드에서 개체를 사용하는 것을 불법(또는 매우 어렵게)으로 만드는 방법을 귀하의 언어로 찾을 수 있습니다.예를 들어 생성자 스레드에서 범위를 객체를 생성하는 코드 블록으로 제한합니다.일단 생성되면 객체를 사용자 스레드로 전달하여 생성자 스레드에 더 이상 해당 객체에 대한 참조가 없는지 확인합니다.

예를 들어 C++에서는

void CreateObject()
{
    Object* sharedObj = new Object();
    PassObjectToUsingThread( sharedObj); // this function would be system dependent
}

그런 다음 생성 스레드에서 객체 생성 후 더 이상 객체에 액세스할 수 없으며 책임은 사용 스레드에 전달됩니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top