Журнал коллизий в многопоточности - PullRequest
1 голос
/ 08 мая 2019

Я хочу регистрировать коллизии в многопоточности с помощью этого простого кода

    public T DataRef
    {
        get
        {
            Collisions.DetectAndSaveCollision(typeof(T).ToString(), Sync);
            lock (Sync)
            {
                return _tData;
            }
        }
        set
        {
            IsInitialized = true;
            Collisions.DetectAndSaveCollision(typeof(T).ToString(), Sync);
            lock (Sync)
            {
                _tData = value;
            }
        }
    }

это метод, который вызывается для добавления элемента в список столкновений

    public static void DetectAndSaveCollision(string value, object lockObject)
    {
        var acquired = false;
        try
        {
            acquired = Monitor.TryEnter(lockObject);
        }
        finally
        {
            if (acquired)
            {
                Monitor.Exit(lockObject);
            }
            else
            {
                lock (lockObject)
                {
                    CollisionCollection.Add(Thread.CurrentThread, value);
                }
            }
        }
    }

но я не уверен, что он свободен от тупиков

1 Ответ

1 голос
/ 08 мая 2019

Это тупик, потому что одновременно берется не более одной блокировки.

Как отмечает Лассе в комментариях, здесь есть условие гонки, потому что вы получаете блокировку Sync дважды подряд. Таким образом, данные не будут точными. Если вам достаточно приблизительных данных, тогда это нормально.

Вы можете исправить гонку, не снимая блокировку сразу же после ее получения. Как то так:

var acquiredImmediately = Monitor.TryEnter(...); //test lock

if (!acquiredImmediately) {
    Log(...);
    Monitor.Enter(...); //retry by blocking
}

CriticalRegion();

Monitor.Exit();

И это требует защиты с finally конечно.

...