2009-06-03 3 views
1

간단한 개체 (레코드) 형태로 데이터를 생성하는 스레드가 있습니다. 스레드는 필터를 성공적으로 통과하고 실제로 대기열에 포함 된 각각에 대해 1,000 개의 레코드를 생성 할 수 있습니다. 객체가 대기열에 추가되면 해당 객체는 읽기 전용입니다..NET의 이중 대기열 생성자 - 소비자 (강제 멤버 변수 flush)

레코드가 필터를 통과하면 획득하는 잠금이 하나 있습니다.이 항목을 producer_queue의 뒤에 추가합니다.

소비자 스레드에서 잠금을 획득하고 producer_queue가 비어 있지 않은지 확인하고 이 consumer_queue를 producer_queue와 같게 설정하고 새 (빈) 큐를 생성 한 다음 producer_queue에서 설정합니다. 추가 잠금이 없으면 empty와 repeat가 될 때까지 consumer_queue를 처리합니다.

모든 것이 아름답게 대부분의 컴퓨터에서 작동하지만 특정 듀얼 쿼드 서버에서는 ~ 1/500k 반복에서 consumer_queue를 읽을 때 완전히 초기화되지 않은 개체가 표시됩니다. 조건은 매우 가볍기 때문에 조건을 감지 한 후 객체를 덤프 할 때 필드의 90 %가 올바른 것입니다.

내 질문은 이것입니다 : 개체에 쓰기가 대기열을 바꿀 때 주 메모리로 플러시되도록하려면 어떻게해야합니까?

편집 : 제조자 스레드

: (위 producer_queue가 m_fillingQueue이다 consumer_queue 위에서 m_drainingQueue이다) 소비자 글

private void FillRecordQueue() { 
    while (!m_done) { 
    int count; 
    lock (m_swapLock) { 
     count = m_fillingQueue.Count; 
    } 
    if (count > 5000) { 
     Thread.Sleep(60); 
    } else { 
     DataRecord rec = GetNextRecord(); 
     if (rec == null) break; 
     lock (m_swapLock) { 
     m_fillingQueue.AddLast(rec); 
     } 
    } 
    } 
} 

는 :

private DataRecord Next(bool remove) { 
    bool drained = false; 
    while (!drained) { 
    if (m_drainingQueue.Count > 0) { 
     DataRecord rec = m_drainingQueue.First.Value; 
     if (remove) m_drainingQueue.RemoveFirst(); 
     if (rec.Time < FIRST_VALID_TIME) { 
     throw new InvalidOperationException("Detected invalid timestamp in Next(): " + rec.Time + " from record " + rec); 
     } 
     return rec; 
    } else { 
     lock (m_swapLock) { 
     m_drainingQueue = m_fillingQueue; 
     m_fillingQueue = new LinkedList<DataRecord>(); 
     if (m_drainingQueue.Count == 0) drained = true; 
     } 
    } 
    } 
    return null; 
} 

소비자는 속도이며 제한적이므로 소비자보다 앞서 나갈 수 없습니다.

내가 보는 동작은 때때로 Time 필드가 DateTime.MinValue로 읽는 것입니다. 그러나 예외를 던질 문자열을 구성 할 때까지는 아무 문제가 없습니다.

+0

명확하지 않습니다. 생산 대기열에서 소비자 대기열과 동일한 변수를 사용하고 있다는 말씀입니까? 그것은 저에게 두드러지는 유일한 작품입니다. 일부 샘플 코드가 도움이 될 수 있습니다. –

+0

잠금에 대한 설명에 따라 'consumer_queue'가 불완전하게 초기화 된 객체를 포함 할 수있는 방법을 알 수 없습니다. 이 질문에 대한 코드 조각을 게시 할 수 있습니까? – jerryjvl

답변

0

이들은 실제로 m_fillingQueue 변수와 상호 작용하는 유일한 방법이며, 그 DataRecord 그것을 생성 GetNextRecord() (판독 전용 속성을 희망?) 후에 변경할 수없는 가정하면, 다음의 코드는 적어도 얼굴 그것은에 나타나는지 맞다.

나는 GregC의 대답을 먼저 확인해야한다고 제안합니다. lock 문은 개체가 목록에 추가되기 전에 rec 변수가 캐시에서 완전히 플러시되도록 보장하기 위해 필요한 모든 메모리 장벽을 포함해야하므로 실패한 컴퓨터가 완전히 업데이트되었는지 확인하십시오 (OS/드라이버/.NET Framework). .

+0

Windows Update FTW. 사용 가능한 마이크로 코드 또는 프로세서 드라이버 업데이트가 없지만 .NET SP1을 설치하면 문제가 해결되었습니다. –

+0

반가워요. 내 사장은 내가 그런 말을 할 때 항상 회의적이다. 소프트웨어로 수정하자. 팀을위한 것. – GregC

+0

어떤 .NET 조각을 업그레이드했는지 궁금 할 수 있습니까? (1.1, 2.0, 3.0, 3.5?) – GregC

2

당신은 분명 : BIOS 업데이트를 통해 멋진 8 코어 박스에 적용된 마이크로 코드가 맞습니까? 최신 프로세서 드라이버를 구하기 위해 Windows Updates를 실행 했습니까?

언뜻보기에 컨테이너를 잠그고있는 것처럼 보입니다. 그래서 저는 시스템 접근법을 권하고 있습니다. 당신이 좋은이 '듀얼 코어 박스에서이 이슈를 보지 못하는 것처럼 들리 네요.