문제

Dictionary<string, someobject>.

편집:그것은 나에게 지적되었다가는 나의 예입니다.내 전체가 의도하지 않았을 참조를 업데이트 루프에서만 업데이트를 서로 다른 값을 기반으로 다른 스레드가 필요 업데이트/데이터를 얻을.을 변경했습니다 반복하는 방법입니다.

해 업데이트 항목에서 내 사전에-키 하나에서 시간과 나이 있는지 궁금을 사용하여 어떤 문제가 잠글 수 있습니다.키의 값은 내 사전에는 것은 어떨까요?

private static Dictionary<string, MatrixElement> matrixElements = new Dictionary<string, MatrixElement>();

//Pseudo-code

public static void UpdateValue(string key)
{
    KeyValuePair<string, MatrixElement> keyValuePair = matrixElements[key];
    lock (keyValuePair.Key)
    {
        keyValuePair.Value  = SomeMeanMethod();
    }
}

는 것은 법정에서 실패하거나?내가 원하는 각 값을 사전에 잠겨있고 즐겁게 놀 수 있는 공간 그래서 잠금(및 업데이트)하나의 값을 잠그지 않습니다.또한 내가 알고 있는 잠금을 들고 오랜 시간다-하지만 데이터가 잘못되었을 때까지 업데이트합니다.

도움이 되었습니까?

해결책

코드 잠금 외부에 액세스 할 수있는 객체를 잠그는 것은 큰 위험입니다. 다른 코드 (어디서나)가 해당 객체를 잠그면 디버깅하기 어려운 교착 상태에 빠질 수 있습니다. 또한 잠그십시오 물체, 참조가 아니므로, 내가 당신에게 사전을 주었을 때, 나는 여전히 열쇠에 대한 참조를 잡고 그들을 잠그면 동일한 객체를 잠그게 할 수 있습니다.

만약에 사전을 완전히 캡슐화하고 키를 직접 생성합니다 (그들은 지나치지 않으면 안전 할 수 있습니다.

그러나 하나의 규칙을 고수하십시오 - 가능할 때마다 잠그는 코드 자체에 잠그는 객체의 가시성을 제한하십시오.

그것이 당신이 이것을 보는 이유입니다.

public class Something
{
  private readonly object lockObj = new object();

  public SomethingReentrant()
  {
    lock(lockObj)    // Line A
    {
      // ...
     }
   }
}

위의 선을 보는 대신 위의 선이 대체되었습니다

  lock(this)

이렇게하면 별도의 객체가 잠겨 있으며 가시성이 제한됩니다.

편집하다 존 스키트 위의 Lockobj는 준비되어 있어야한다는 것을 올바르게 관찰했습니다.

다른 팁

아니요, 이것은 작동하지 않습니다.

그 이유는 문자열 인턴. 이것은 다음을 의미합니다.

string a = "Something";
string b = "Something";

둘 다 같은 대상입니다! 따라서 프로그램의 다른 부분 (예 : 동일한 개체의 다른 인스턴스)도 같은 문자열을 잠그고 싶다면 실수로 잠금 경합을 만들 수 있기 때문에 문자열을 잠그면 안됩니다. 아마도 교착 상태 일 수도 있습니다.

그래도 비 스트링으로 자유롭게 해보십시오. 최선의 명확성을 위해, 나는 항상 별도의 잠금 객체를 만드는 것이 개인적인 습관으로 만듭니다.

class Something
{
    bool threadSafeBool = true;
    object threadSafeBoolLock = new object(); // Always lock this to use threadSafeBool
}

나는 당신도 똑같이하는 것이 좋습니다. 모든 행렬 셀에 대한 잠금 객체와 함께 사전을 만듭니다. 그런 다음 필요할 때이 물체를 잠그십시오.

추신. 반복하는 컬렉션을 변경하는 것은 그리 좋지 않습니다. 대부분의 컬렉션 유형에서도 예외가 발생합니다. 쌍이 아니라 항상 일정하다면 키 목록을 반복하십시오.

참고:나는 가정의 예외를 수정할 때 수집하는 동안 반복은 이미 수정

사전하지 않은 스레드에 안전한 컬렉션을 의미하는,그것은 안전함을 수정하고 읽기 컬렉션에서 다른 스레드의 없이 외부 동기화합니다.Hashtable(했다?) 스레드에 안전한 중 하나가 많 독자는 시나리오 그러나 사전에 서로 다른 내부터 데이터 구조와 상속 하지 않습니다.

이 의미는 수정할 수 없습니다 귀하의 사전 동안 당신은에 액세스하는 그것을 읽거나 쓰기 다른 스레드에서,그것은 단지 침 내부터 데이터 구조입니다.잠그에서 키를 보호하지 않 내부터 데이터 구조이기 때문에,하는 동안 수정하는 매우 중요한 사람이 될 수 있는 독서 서로 다른 키를 사전에서 또 다른 스레드가 있습니다.도 보장할 수 있는 경우에는 귀하의 모든 키들이 동일한 개체에(같은 말에 대한 문자열 인턴),이하지 않에 당신을 가져올 안전 측면에 있습니다.예제:

  1. 당신은 잠금 키고하기 시작한 수정 사전
  2. 다른 스레드를 시도하는 가치를 얻기 위한 핵심있는 일을 가을 같은 버킷으로 잠근다.이뿐만 아니라 때 hashcodes 의 두 물체가 동일한지만,더 많은 자주 때 차이%tableSize 은 동일합니다.
  3. 모두 스레드에 액세스하는 동일한 물통(연결된 키 목록과 동일한 차이%tableSize 값)

이 없는 경우 이러한 키,사전에서 첫 번째 스레드가 시작됩 목록 수정하고,두 번째 스레드 가능성을 읽는 불완전한 상태입니다.

는 경우 이러한 키 이미 존재,구현 정보의 사전 수 있는 여전히 수정하는 데이터 구조,예를 들어 이동 최근에 액세스 열쇠를 머리의 목록 빠른 검색을 위해.할 수 없습에 의존하고 구현하세요.

많은 경우에는,당신이 손상되어 사전입니다.그래서 당신이 있어야 외부 동기화체(또는 사전을 사용한다면에 노출되지 않 공개)및 잠금 시간 중에 전체 작업입니다.필요하신 경우 더 세분화 되면 잠금 작업이 걸릴 수 있는 장시간을 복사할 수 있습니다 키를 업데이트해야 할,반복,그것을 전체 잠금 사전 동안 하나의 키를 업데이트(는 것을 잊지 않을 확인하는 핵심은 여전히 있다)및 릴리스를 다른 스레드를 실행합니다.

내가 착각하지 않으면 원래 의도는 전체 사전을 잠그는 대신 단일 요소를 잠그는 것이 었습니다 (DB의 테이블 레벨 잠금 대 행 레벨 잠금).

여기에 많은 사람들이 설명했듯이 사전의 열쇠를 잠글 수 없습니다.

당신이 할 수있는 것은 실제 사전에 해당하는 내부 잠금 객체를 유지하는 것입니다. 따라서 당신이 당신의 dictionary [key1]에 편지를 쓰고 싶을 때, 먼저 InternallocksDictionary [key1]에 잠겨 있습니다. 따라서 단일 스레드 만 당신의 dictionary에 쓸 것입니다.

(너무 깨끗하지 않음) 예일 수 있습니다 여기에서 찾았습니다.

방금 이것을 발견했고 몇 년 전에 쓴 몇 가지 코드를 공유했다고 생각했습니다.

 using (var lockObject = new Lock(hashedCacheID))
 {
    var lockedKey = lockObject.GetLock();
    //now do something with the dictionary
 }

잠금 클래스

class Lock : IDisposable
    {
        private static readonly Dictionary<string, string> Lockedkeys = new Dictionary<string, string>();

        private static readonly object CritialLock = new object();

        private readonly string _key;
        private bool _isLocked;

        public Lock(string key)
        {
            _key = key;

            lock (CritialLock)
            {
                //if the dictionary doesnt contain the key add it
                if (!Lockedkeys.ContainsKey(key))
                {
                    Lockedkeys.Add(key, String.Copy(key)); //enusre that the two objects have different references
                }
            }
        }

        public string GetLock()
        {
            var key = Lockedkeys[_key];

            if (!_isLocked)
            {
                Monitor.Enter(key);
            }
            _isLocked = true;

            return key;
        }

        public void Dispose()
        {
            var key = Lockedkeys[_key];

            if (_isLocked)
            {
                Monitor.Exit(key);
            }
            _isLocked = false;
        }
    }

당신의 예에서, 당신은 당신이하고 싶은 일을 할 수 없습니다!

당신은 얻을 것입니다 System.InvalidOperationException 메시지와 함께 수집이 수정되었습니다. 열거 작업이 실행되지 않을 수 있습니다.

다음은 다음과 같이 증명할 예입니다.

using System.Collections.Generic;
using System;

public class Test
{
    private Int32 age = 42;

    static public void Main()
    {
       (new Test()).TestMethod();
    }

    public void TestMethod()
    {
        Dictionary<Int32, string> myDict = new Dictionary<Int32, string>();

        myDict[age] = age.ToString();

        foreach(KeyValuePair<Int32, string> pair in myDict)
        {
            Console.WriteLine("{0} : {1}", pair.Key, pair.Value);
            ++age;
            Console.WriteLine("{0} : {1}", pair.Key, pair.Value);
            myDict[pair.Key] = "new";
            Console.WriteLine("Changed!");
        }
    }   
}

출력은 다음과 같습니다.

42 : 42
42 : 42

Unhandled Exception: System.InvalidOperationException: Collection was modified; enumeration operation may not execute.
   at System.ThrowHelper.ThrowInvalidOperationException(ExceptionResource resource)
   at System.Collections.Generic.Dictionary`2.Enumerator.MoveNext()
   at Test.TestMethod()
   at Test.Main()

몇 가지 잠재적 인 문제를 볼 수 있습니다.

  1. 문자열을 공유 할 수 있으므로 다른 이유에 대해 누가 그 핵심 객체를 잠그고 있을지 알지 못합니다.
  2. 문자열이있을 수 있습니다 ~ 아니다 공유 : "key1"값으로 하나의 문자열 키에서 잠글 수 있으며 다른 코드는 문자 "key1"을 포함하는 다른 문자열 객체를 가질 수 있습니다. 사전에 그들은 동일한 열쇠이지만 잠금에 관한 한 다른 물체라고 우려합니다.
  3. 잠금은 가치 객체 자체의 변화를 방해하지 않을 것입니다. matrixElements[someKey].ChangeAllYourContents()
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top