C# 如何动态锁定字符串,但从内存中删除锁定对象
我有以下情况: 我的项目中有很多线程,每个线程一次处理一个“键” 两个线程不能同时处理同一个“密钥”,但我的项目处理大量的密钥,因此我不能在内存中存储“密钥”,我需要在内存中存储一个线程正在处理一个“密钥”,如果另一个线程试图处理同一个“密钥”,这个线程将在C# 如何动态锁定字符串,但从内存中删除锁定对象,c#,multithreading,C#,Multithreading,我有以下情况: 我的项目中有很多线程,每个线程一次处理一个“键” 两个线程不能同时处理同一个“密钥”,但我的项目处理大量的密钥,因此我不能在内存中存储“密钥”,我需要在内存中存储一个线程正在处理一个“密钥”,如果另一个线程试图处理同一个“密钥”,这个线程将在lock子句中等待 现在我有以下结构: public class Lock { private static object _lockObj = new object(); private sta
lock
子句中等待
现在我有以下结构:
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();
}
}
}
公共类锁
{
私有静态对象_lockObj=新对象();
私有静态列表_lockListValues=new List();
公共静态void Execute(对象值、操作)
{
锁
{
如果(!\u lockListValues.Contains(value))
_lockListValues.Add(value);
}
锁(_lockListValues.First(x=>x.Equals(value)))
{
action.Invoke();
}
}
}
它工作正常,问题是没有从内存中删除键。最大的问题是多线程特性,因为在任何时候都可以处理“密钥”
如果没有独立于密钥的全局锁,我如何解决此问题?抱歉,但不,这不是应该采用的方法 首先,您谈到键,但您将键作为类型对象存储在列表中,然后使用LINQ进行搜索以从列表中获取该对象 字典里有这类东西 第二,对象模型,通常最好在某个类周围实现某个对象的锁定,使其美观、干净: 比如:
使用System.Collections.Concurrent;
公共锁定对象
{
公共只读数据;
公共只读int-id;
私有只读对象obj=新对象();
锁定对象(内部id,T数据)
{
this.id=id;
这个数据=数据;
}
//通常,如果您有与某些数据相关的操作,
//接受更好
//该数据作为参数
公共无效调用(操作)
{
锁(obj)
{
行动(数据);
}
}
}
//现在,它是一个应用某些操作的并发安全对象
//同时处理给定数据,无论它是如何存储的。
//但这仍然是最好的主意:
并行词典=
新的ConcurrentDictionary();
//您可以同时插入、读取、删除所有对象。
但是,最好的事情还在后头呢!:)你可以使它锁自由,非常容易
EDIT1:
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);
});
使用系统;
使用系统线程;
使用System.Collections.Concurrent;
公共类ConcurrentInvoke
{
//我们讨厌锁():)
私有类数据
{
公共只读TData数据;
私人int标志;
专用数据(TData数据)
{
这个数据=数据;
}
公共静态bool包含(ConcurrentDictionary dict,TTKey)
{
返回dict.ContainsKey(键);
}
公共静态bool TryAdd(ConcurrentDictionary dict、TTKey、TData数据)
{
返回dict.TryAdd(键,新数据(数据));
}
//如果,
//不存在,,
//删除已在进行的密钥,
//在进程中调用键的操作
公共静态bool TryRemove(ConcurrentDictionary dict、TTKey、Action\u removed=null)
{
数据=空;
如果(!dict.TryGetValue(key,out data))返回false;
var访问=联锁。比较交换(ref data.flag,1,0)=0;
如果(!access)返回false;
数据data2=null;
var removed=dict.TryRemove(键,输出数据2);
联锁交换(参考数据标志,0);
如果(已删除&操作已删除!=null)操作已删除(键,data2.data);
移除返回;
}
//如果,
//不存在,,
//删除已在进行的密钥,
//在进程中调用键的操作
公共静态bool TryInvokeAction(ConcurrentDictionary dict,TTKey key,Action invoke\u Action=null)
{
数据=空;
if(invoke_action==null | |!dict.TryGetValue(key,out data))返回false;
var访问=联锁。比较交换(ref data.flag,1,0)=0;
如果(!access)返回false;
调用_操作(键、数据、数据);
联锁交换(参考数据标志,0);
返回true;
}
}
私有的
只读
并行词典=
新的ConcurrentDictionary()
;
公共bool包含(TKey)
{
返回数据。包含(dict,key);
}
公共bool TryAdd(TKey键,TValue值)
{
返回数据.TryAdd(dict、key、value);
}
public bool TryRemove(TKey,Action removed=null)
{
返回数据.TryRemove(dict,key,remove);
}
公共bool TryInvokeAction(TKey键,Action调用)
{
返回Data.TryInvokeAction(dict、key、invoke);
}
}
ConcurrentInvoke concurrent_invoke=新的ConcurrentInvoke();
concurrent_invoke.TryAdd(1,“字符串1”);
concurrent_invoke.TryAdd(2,“字符串2”);
concurrent_invoke.TryAdd(3,“字符串3”);
并发调用TryRemove(1);
并发调用.TryInvokeAction(3,(键,值)=>
{
WriteLine(“InvokingAction[key:{0},vale:{1}”,key,value);
});
我修改了我发布的KeyedLock
类,在内部使用该类,而不是SemaphoreSlim
s。我希望使用专门的同步锁定机制可以提供更好的性能,但实际上我看不到任何区别。我发布它是因为它添加了
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);
});
public class KeyedMonitor<TKey>
{
private readonly Dictionary<TKey, (object, int)> _perKey;
private readonly Stack<object> _pool;
private readonly int _poolCapacity;
public KeyedMonitor(IEqualityComparer<TKey> keyComparer = null,
int poolCapacity = 10)
{
_perKey = new Dictionary<TKey, (object, int)>(keyComparer);
_pool = new Stack<object>(poolCapacity);
_poolCapacity = poolCapacity;
}
public ExitToken Enter(TKey key)
{
var locker = GetLocker(key);
Monitor.Enter(locker);
return new ExitToken(this, key);
}
public bool TryEnter(TKey key, int millisecondsTimeout)
{
var locker = GetLocker(key);
var acquired = Monitor.TryEnter(locker, millisecondsTimeout);
if (!acquired) ReleaseLocker(key, withMonitorExit: false);
return acquired;
}
public void Exit(TKey key) => ReleaseLocker(key, withMonitorExit: true);
private object GetLocker(TKey key)
{
object locker;
lock (_perKey)
{
if (_perKey.TryGetValue(key, out var entry))
{
int counter;
(locker, counter) = entry;
counter++;
_perKey[key] = (locker, counter);
}
else
{
lock (_pool) locker = _pool.Count > 0 ? _pool.Pop() : null;
if (locker == null) locker = new object();
_perKey[key] = (locker, 1);
}
}
return locker;
}
private void ReleaseLocker(TKey key, bool withMonitorExit)
{
object locker; int counter;
lock (_perKey)
{
if (_perKey.TryGetValue(key, out var entry))
{
(locker, counter) = entry;
counter--;
if (counter == 0)
_perKey.Remove(key);
else
_perKey[key] = (locker, counter);
}
else
{
throw new InvalidOperationException("Key not found.");
}
}
if (withMonitorExit) Monitor.Exit(locker);
if (counter == 0)
lock (_pool) if (_pool.Count < _poolCapacity) _pool.Push(locker);
}
public readonly struct ExitToken : IDisposable
{
private readonly KeyedMonitor<TKey> _parent;
private readonly TKey _key;
public ExitToken(KeyedMonitor<TKey> parent, TKey key)
{
_parent = parent; _key = key;
}
public void Dispose() => _parent?.Exit(_key);
}
}
var locker = new KeyedMonitor<string>();
using (locker.Enter("Hello"))
{
DoSomething(); // with the "Hello" resource
}