如何动态锁定字符串,但从内存中删除锁定对象
本文关键字:锁定 内存 对象 删除 字符串 何动态 动态 | 更新日期: 2023-09-27 18:22:31
我有以下情况:
我的项目中有很多线程,每个线程处理一个"线程";键";按时间。
两个线程不能处理相同的"线程";键";同时,但我的项目过程中缺少密钥,所以我无法存储";键";在内存上,我需要在内存上存储线程正在处理";键";并且如果另一个线程试图处理相同的"线程";键";该线程将在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."
。如果抛出其中任何一个,则表明上述实现中存在逻辑错误。