2010-07-17 5 views
1

구조체 "타일"이 포함 된 거대한 배열이 있습니다. 프로그램 메신저는 2D 게임이며, 다른 플레이어 (다른 스레드에 의해 처리됨)가 동시에 같은 타일에 위치를 기록하는 것을 원하지 않으며 두 가지가 궁금합니다. 두 개의 스레드가 안전하게 동시에 두 개의 서로 다른 위치에 쓸 수 있습니까?이 배열의 하나의 인덱스 만 잠그는 효과적인 방법이 있습니까?구조체의 배열, 멀티 스레딩, 다른 인덱스에 동시에 쓸 수 있습니까?

답변

2

예, 다른 스레드에서 동시에 다른 위치에 쓸 수 있습니다.

잠금을 수행하려면 잠금 배열을 작성하고 간단한 해싱 기술을 사용하여 작성중인 위치에 따라 잠금을 선택해야합니다. 예를 들어 :

class TileArray 
{ 
    private static readonly int numLocks = 16; 
    private object[] locks = (from i in Range(0, numLocks) select new object()).ToArray(); 
    private Tile[] tiles = hugeTileArray(); 

    ... 

    public Tile this[int i] 
    { 
     get { return tiles[i]; } 
     set 
     { 
      lock (locks[i % numLocks]) 
       tiles[i] = value; 
     } 
    } 
} 

이것은 잠금 엄청나게을 만들 필요가 피할 수 있지만, 여전히 최소한으로 잠금 경합을 유지합니다. 프로파일 링에 따라 numLocks를 위 또는 아래로 설정할 수 있습니다. 효율적인 모듈로 계산을 위해서는 2의 제곱을 유지하십시오.

최종 세부 사항 : 앨리어싱 효과에주의하십시오. 예를 들어, 16의 배수가 약간의 이상한 이유로 스레드에서 매우 인기가있을 수 있습니다.이 경우 경합이 지붕을 통과하게됩니다. 이 경우 더 강력한 해시가 필요합니다. 아마도 (uint)i.GetHashCode() % numLocks이 실행될 것입니다. 그러나 무엇을 Int32.GetHashCode이 수행할지 모르겠습니다. 숫자 자체를 반환 할 수 있습니다. 이것이 실패하면 Bob Jenkins에서 훔칠 수 있습니다.

+0

아, 고마워. :) 동등한 크기의 물체 배열을 가지고 자물쇠를 잡는 것에 대해 생각해 보았지만, 더 이해가됩니다. – Alle

+0

그런 식으로하면 1 차원 배열로 변경해야합니다. 그렇습니까? – Alle

+0

@Alle : 원칙은 위치의 해시를 생성하는 것입니다. 1 차원 배열이라면'i % numLocks'의 간단한 문제입니다. 그러나 이것은 특별한 경우입니다. 2 차원 배열을 사용하는 경우 'i <0x10000'인 동안 'hash (i << 16 + j) % numLocks' (여기서'hash '는 임의의 올바른 정수 해시 함수)를 사용할 수 있습니다. –

0

원하는 작업을 기본적으로 지원하지 않습니다. 여러 스레드가 동시에 같은 배열에 액세스 할 수 있지만 동기화 등을 통해 데이터 일관성을 처리해야합니다. 따라서 인덱스 별 잠금 (데이터베이스가 트랜잭션에서 수행하는 것과 유사)을 구현하는 것이 가능하지만, 이것이 사용자가하려는 작업에 적합한 방법인지 확신 할 수 없습니다. 배열을 사용하여 시작하는 이유는 무엇입니까?

+0

필자는 필요한 빠른 액세스가 있어야한다고 생각하고 2D 게임이므로 X 및 Y 좌표를 인덱스로 사용할 수 있습니다. – Alle

0

나는 lock statement을 사용하여 배열에 액세스하고 스레드간에 공유되는 코드 스레드를 안전하게 만들 수 있다고 생각합니다.

+0

나는 그것을 시도했지만 구조체가 참조 형 또는 이와 비슷한 것이 아니라고 생각한다. – Alle

+0

또한 배열의 인덱스를 보호하지 못한다. 이는 질문이 요구하지 않을 수도있다. – Lucero

1

잠금을 명시 적으로 사용하지 않고도 읽고 쓸 수있는 Interlocked.CompareExchange 함수를 사용할 수 있습니다. 당신이 클래스에 Tile 구조체를 변환해야합니다 물론

public class Example 
{ 
    private Tile[] m_Array; 

    public Tile this[int index] 
    { 
    get { return Interlocked.CompareExchange(ref m_Array[i], null, null); } 
    set { Interlocked.CompareExchange(ref m_Array[i], value, m_Array[i]); } 
    } 
} 

이 작업을 수행 할 수 있습니다.