Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/318.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何动态锁定字符串,但从内存中删除锁定对象_C#_Multithreading - Fatal编程技术网

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
}