2010-02-26 2 views
2

사용자가 선택할 수있는 객체 목록을 표시하는 응용 프로그램을 작성한 다음 PropertyGrid 컨트롤을 통해 속성을보고 편집 할 수 있습니다. 개체의 속성은 보조 스레드를 사용하여 파일에서 정보를 추출하는 시간이 많이 걸리는 프로세스로 채워집니다. 그러나 추출 프로세스가 진행되는 동안 사용자가 다른 객체를 계속 볼 수있게하고 싶습니다.개체 컬렉션에 대한 다중 스레드 액세스를 어떻게 제어합니까?

my previous 개의 질문에 대한 답변을 읽은 후. 그것은 추출 프로세스에 의해 쓰여지는 속성이 속성 그리드를 통해 사용자가 편집 할 수있는 속성과 교차하지 않기 때문에 발생합니다. 동시에 개체를 편집하는 두 스레드에 문제가 있어서는 안됩니다. 믿을 수 없을 정도로 재수가 많고 속성 그리드가 비 원자 적 쓰기 도중에 객체를 읽게되면 사용자가 잘못된 값을 볼 수도 있습니다.

그러나 아직 사용자가 추출 중에있는 객체를 편집하거나 볼 수 없도록 설정하는 방법을 알고 싶습니다. 필자는 멀티 스레딩을 처음 접했지만 실제로 읽은 대부분의 예제는 실제 관심 객체에 대한 액세스를 잠그기 위해 사용되는 별도의 토큰 객체를 보여줍니다. 내 다른 previous question에 대한 답변은 잠금과 같은 별도의 개체를 만드는 것이 일반적이라는 것을 확인했습니다.

그래서 지금 내가 알고 싶은 것은 내 물건에 많은 양의 컬렉션이있는 경우 어떻게 처리할까요? 나는 현재 추출 된 경우 사용자가 선택하는 객체를 표시하는 속성 격자를 막는 잠금을 만들고 싶습니다.

실제 컬렉션과 동기화 된 잠금 객체 모음을 별도로 만들어야합니까? 개체가 주 컬렉션에 추가되거나 제거되면 잠금 컬렉션에서 잠금 개체를 추가하거나 제거해야합니까?

별도의 토큰 잠금 개체를 만드는 대신 실제 개체를 잠급니다.

객체가 쓰여지는 동안 속성 격자가 확인할 수있는 객체에 "IsBeingExtracted"부울 속성을 추가하는 것은 어떻습니까? 이것은 추출 과정의 맨 처음과 마지막에 설정됩니다.

또는 현재 추출 된 현재 (있는 경우) 개체를 참조하는 어딘가에 정적 필드 어때? 그런 다음 속성 격자는 표시 할 최신 객체가이 정적 필드에서 참조하는 객체가 아닌지 확인할 수 있습니다. 물론 추출 스레드가 여러 개있는 경우에는 물론 작동하지 않습니다.

가장 좋은 방법/올바른 방법은 무엇입니까? 개인적으로 부울 속성 옵션이 가장 좋지만 실제로 생각하는 다른 사람들이 생각하는 것을 알고 싶습니다.

답변

1

개체를 보유하고있는 컬렉션을 SynchronizedCollection<T>으로 만들 수 없습니까? 한 번에 하나의 스레드 만 개체를 ​​추가하거나 개체에 액세스 할 수 있는지 확인합니다. 그런 다음 각 개체의 속성에 대한 액세스를 동기화하는 방법에 대해 걱정하지 말고 개체가 채워질 때까지 개체를 컬렉션에 추가하지 마십시오. 이 같은

뭔가가 :

private readonly ICollection<Item> Items = new SynchronizedCollection<Item>(); 

// Run this on the background thread. 
public void PopulateItems() 
{ 
    using (var file = File.OpenRead("BigFile.txt")) 
    using (var reader = new StreamReader(file)) 
    { 
     while (!reader.EndOfStream) 
     { 
      var item = new Item(); 
      PopulateItem(item); 
      Items.Add(item); 
     } 
    } 
} 

public void PopulateItem(Item item) 
{ 
    // Do time-consuming work. 
} 

속성 그리드 행복하게 때문에이 목록에 표시되는 시간에 의해 개체와 원하는 무엇이든 할 수 있고, 추출 스레드가 완료된다. 명시 적 잠금이 필요하지 않습니다.

0

개체 컬렉션을 사전으로 설정 한 다음 키를 잠급니다.

-1

시간 제한이있는 ManualResetEvent 객체를 사용하는 것이 가장 좋은 방법이라고 생각합니다. 그렇게하면 사용자에게 압축이 풀렸다 고 알리고 몇 초 후에 다시 시도 할 수 있습니다.

public class Item : IDisposable // I know it is a horrible class name... 
{ 
    private readonly ManualResetEvent accessibleEvent = new ManualResetEvent(false); 

    public void Extract() 
    { 
     try 
     { 
      // ..... 
     } 
     finally 
     { 
      accessibleEvent.Set(); // unlock    
     } 
    } 

    public void Edit() 
    { 
     if (!accessibleEvent.WaitOne(1000)) // wait 1 second 
     { 
      // notify user?  
     } 

     // .... 
    } 

    public void Dispose() 
    { 
     ((IDisposable)accessibleEvent).Dispose(); 
    } 
} 
+0

잠금 장치를 두 번째 이상 보유해야하는 이유는 무엇입니까? 동기화 스레드의 일부는 경합에있을 수있는 시간의 길이를 최소화합니다. –

+0

@Rory - 잠금을 유지할 시간이 아니라 항목을 편집하기 위해 대기하는 시간입니다. – ChaosPandion

0

일반적으로 하나 이상의 잠금을 사용하면 달성하려는 동시성의 정도에 따라 다릅니다.

많은 잠금 (예 : 글로벌 잠금)이 적 으면 많은 작업이 잠금을두고 경쟁하고 서로의 실행을 막을 수 있기 때문에 동시성이 낮아집니다.

잠금이 많을수록 더 많은 동시성을 얻을 수 있지만 잠금 관리에 더 많은 오버 헤드가 있습니다.

수정중인 개체 인 잠금을 사용하면 잠금으로 보호하려는 개체가이 개체 인 경우에만 의미가 있습니다. 별도의 객체를 사용하는 많은 예가 보일 것입니다. 그 이유는 보호 범위에 관해서는 필요가 없기 때문입니다.

특정 경우에 보호 대상이 무엇인지 알 수 없습니다. 백그라운드 프로세스 또는 사용자가 객체의 속성을 동시에 수정하는 것을 방지하려고합니까? 사용자가 한 번에 두 가지 이상의 작업을 수행 할 수 없으므로 많은 동시성이 필요하지 않으므로 많은 잠금이 필요하지 않습니다. 속성 격자가 편집 모드로 들어가고 백그라운드 프로세스가 편집중인 동일한 속성을 설정하려고 할 때 단일 잠금을 사용합니다 (그렇지 않으면 잠금이 필요하지 않습니다).

관련 문제