如何动态锁定字符串,但从内存中删除锁定对象



我有以下情况:

我的项目中有很多线程,每个线程处理一个"线程";键";按时间。

两个线程不能处理相同的"线程";键";同时,但我的项目过程中缺少密钥,所以我无法存储";键";在内存上,我需要在内存上存储线程正在处理";键";并且如果另一个线程试图处理相同的"线程";键";该线程将在CCD_ 1子句中等待。

现在我有以下结构:

public class Lock
{
    private static object _lockObj = new object();
    private static List<object> _lockListValues = new List<object>();
    public static void Execute(object value, Action action)
    {
        lock (_lockObj)
        {
            if (!_lockListValues.Contains(value))
                _lockListValues.Add(value);
        }
        lock (_lockListValues.First(x => x.Equals(value)))
        {
            action.Invoke();
        }
    }
}

它工作正常,问题是钥匙没有从内存中取出。最大的问题是多线程特性,因为在任何时候;键";可以进行处理。

如果没有独立于密钥的全局锁,我怎么能解决这个问题?

对不起,但不,这不是应该做的。

首先,您谈到密钥,但您将密钥存储为List中的类型对象,然后使用LINQ进行搜索以从列表中获取密钥。

因为这种东西在字典里。

第二,对象模型,通常最好在某个类周围实现某个对象的锁定,使其美观干净:

类似:

using System.Collections.Concurrent;

public LockedObject<T>
{
    public readonly T data;
    public readonly int id;
    private readonly object obj = new object();
    LockedObject(int id, T data)
    {
        this.id = id;
        this.data = data;
    }
    //Usually, if you have Action related to some data,
    //it is better to receive
    //that data as parameter
    public void InvokeAction(Action<T> action)
    {
        lock(obj)
        {
            action(data);
        }
    }
}
//Now it is a concurrently safe object applying some action
//concurrently on given data, no matter how it is stored.
//But still, this is the best idea:

ConcurrentDictionary<int, LockedObject<T>> dict =
new ConcurrentDictionary<int, LockedObject<T>>();
//You can insert, read, remove all object's concurrently.

但是,最好的事情还没有到来!:)你可以让它很容易地锁定!

第1版:

ConcurrentInvoke,类似字典的集合,用于对数据进行并发安全调用操作。在给定的键上一次只能有一个操作。

using System;
using System.Threading;
using System.Collections.Concurrent;

public class ConcurrentInvoke<TKey, TValue>
{
    //we hate lock() :)
    private class Data<TData>
    {
        public readonly TData data;
        private int flag;
        private Data(TData data)
        {
            this.data = data;
        }
        public static bool Contains<TTKey>(ConcurrentDictionary<TTKey, Data<TData>> dict, TTKey key)
        {
            return dict.ContainsKey(key);
        }
        public static bool TryAdd<TTKey>(ConcurrentDictionary<TTKey, Data<TData>> dict, TTKey key, TData data)
        {
            return dict.TryAdd(key, new Data<TData>(data));
        }
        // can not remove if,
        // not exist,
        // remove of the key already in progress,
        // invoke action of the key inprogress
        public static bool TryRemove<TTKey>(ConcurrentDictionary<TTKey, Data<TData>> dict, TTKey key, Action<TTKey, TData> action_removed = null)
        {
            Data<TData> data = null;
            if (!dict.TryGetValue(key, out data)) return false;
            var access = Interlocked.CompareExchange(ref data.flag, 1, 0) == 0;
            if (!access) return false;
            Data<TData> data2 = null;
            var removed = dict.TryRemove(key, out data2);
            Interlocked.Exchange(ref data.flag, 0);
            if (removed && action_removed != null) action_removed(key, data2.data);
            return removed;
        }
        // can not invoke if,
        // not exist,
        // remove of the key already in progress,
        // invoke action of the key inprogress
        public static bool TryInvokeAction<TTKey>(ConcurrentDictionary<TTKey, Data<TData>> dict, TTKey key, Action<TTKey, TData> invoke_action = null)
        {
            Data<TData> data = null;
            if (invoke_action == null || !dict.TryGetValue(key, out data)) return false;
            var access = Interlocked.CompareExchange(ref data.flag, 1, 0) == 0;
            if (!access) return false;
            invoke_action(key, data.data);
            Interlocked.Exchange(ref data.flag, 0);
            return true;
        }
    }
    private 
    readonly
    ConcurrentDictionary<TKey, Data<TValue>> dict =
    new ConcurrentDictionary<TKey, Data<TValue>>()
    ;
    public bool Contains(TKey key)
    {
        return Data<TValue>.Contains(dict, key);
    }
    public bool TryAdd(TKey key, TValue value)
    {
        return Data<TValue>.TryAdd(dict, key, value);
    }
    public bool TryRemove(TKey key, Action<TKey, TValue> removed = null)
    {
        return Data<TValue>.TryRemove(dict, key, removed);
    }
    public bool TryInvokeAction(TKey key, Action<TKey, TValue> invoke)
    {
        return Data<TValue>.TryInvokeAction(dict, key, invoke);
    }
}


ConcurrentInvoke<int, string> concurrent_invoke = new ConcurrentInvoke<int, string>();
concurrent_invoke.TryAdd(1, "string 1");
concurrent_invoke.TryAdd(2, "string 2");
concurrent_invoke.TryAdd(3, "string 3");
concurrent_invoke.TryRemove(1);
concurrent_invoke.TryInvokeAction(3, (key, value) =>
{
    Console.WriteLine("InvokingAction[key: {0}, vale: {1}", key, value);
});

以下是基于ConcurrentDictionary<K,V>集合的Lock类的健壮且高性能的实现:

public static class Lock
{
    private static readonly ConcurrentDictionary<object, Entry> _entries = new();
    private readonly record struct Entry(object Locker, int RefCount);
    public static void Execute(object key, Action action)
    {
        object locker = GetLocker(key);
        bool lockTaken = false;
        try
        {
            Monitor.Enter(locker, ref lockTaken);
            action();
        }
        finally
        {
            if (lockTaken) Monitor.Exit(locker);
            ReleaseLocker(key, locker);
        }
    }
    private static object GetLocker(object key)
    {
        Entry entry = _entries.AddOrUpdate(key,
            static _ => new Entry(new object(), 1),
            static (_, entry) => entry with { RefCount = entry.RefCount + 1 });
        return entry.Locker;
    }
    private static void ReleaseLocker(object key, object locker)
    {
        while (true)
        {
            bool exists = _entries.TryGetValue(key, out Entry entry);
            if (!exists)
                throw new InvalidOperationException("Key not found.");
            if (!ReferenceEquals(entry.Locker, locker))
                new InvalidOperationException("Unknown locker.");
            if (entry.RefCount > 1)
            {
                Entry newEntry = entry with { RefCount = entry.RefCount - 1 };
                if (_entries.TryUpdate(key, newEntry, entry))
                    break;
            }
            else
            {
                if (_entries.TryRemove(KeyValuePair.Create(key, entry)))
                    break;
            }
        }
    }
}

这个实现基于一个类似问题的答案:基于密钥的异步锁定。你可以看看这个答案来详细解释它是如何工作的。

决不应抛出两个InvalidOperationException异常"Key not found.""Unknown locker."。如果抛出其中任何一个,则表明上述实现中存在逻辑错误。

最新更新