如何在C#中锁定整数?

Wal*_*ssa 20 .net c# locking

有没有办法在C#中锁定一个整数?整数不能与锁一起使用,因为它们是盒装的(并且只锁定引用上的锁).

场景如下:我有一个基于论坛的网站,具有审核功能.我想要做的是确保在任何给定时间不超过一个主持人可以调节帖子.为此,我想锁定帖子的ID.

到目前为止我有几个想法(例如使用字典<int,object>),但我正在寻找一种更好,更清洁的方法.

有什么建议?

con*_*tor 26

我喜欢这样做

public class Synchronizer {
    private Dictionary<int, object> locks;
    private object myLock;

    public Synchronizer() {
        locks = new Dictionary<int, object>();
        myLock = new object();
    }

    public object this[int index] {
        get {
            lock (myLock) {
                object result;
                if (locks.TryGetValue(index, out result))
                    return result;

                result = new object();
                locks[index] = result;
                return result;
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,简单地锁定一个int(每次使用相同的同步器)

lock (sync[15]) { ... }
Run Code Online (Sandbox Code Playgroud)

当给出相同的索引两次时,此类返回相同的锁对象.当一个新索引到来时,它会创建一个对象,返回它,然后将它存储在字典中以供下次使用.

它可以很容易地更改为使用任何struct或值类型一般工作,或者static使得不必传递同步器对象.

  • @omu:不在.Net 3.字典即使只是阅读也不是线程安全的.在.Net 4中,您可以使用ConcurrentDictionary并通过调用GetOrAdd来完全避免锁定. (3认同)
  • 另外,请记住,如果将其设置为静态,则它永远不会被垃圾收集,并且可能会造成某种内存泄漏 - 对于您曾经锁定的每个 int,堆中都会有一个对象。 (2认同)
  • 如果用 MemoryCache 对象替换 Dictionary ,则可以使用绝对过期参数对值设置过期时间(以避免字典无限增长)。 (2认同)
  • @Joshua:你必须确保这些值在它们被锁定时不会过期. (2认同)

Gre*_*ech 6

如果它是一个网站,那么使用进程内锁可能不是最好的方法,就好像你需要将网站扩展到多个服务器,或添加另一个托管API的网站(或任何其他需要其他进程访问相同的网站)数据存在)然后你所有的锁定策略立即无效.

我倾向于研究基于数据库的锁定.最简单的方法是使用乐观锁定,例如上次更新帖子的时间戳,以及拒绝对帖子进行的更新,除非时间戳匹配.


Bri*_*ian 5

我已经阅读了很多评论,提到锁定对Web应用程序来说并不安全,但除了Web场之外,我还没有看到任何解释原因.我有兴趣听取反对它的论点.

我有类似的需求,虽然我在硬盘上缓存重新调整大小的图像(这显然是一个本地操作,因此Web场景不是问题).

这是@Configurator发布的重做版本.它包含一些@Configurator不包含的功能:

  1. 解锁:确保列表不会增长到不合理的大(我们有数百万张照片,每个都可以有不同的大小).
  2. 通用:允许基于不同的数据类型(例如int或string)进行锁定.

这是代码......

/// <summary>
/// Provides a way to lock a resource based on a value (such as an ID or path).
/// </summary>
public class Synchronizer<T>
{

    private Dictionary<T, SyncLock> mLocks = new Dictionary<T, SyncLock>();
    private object mLock = new object();

    /// <summary>
    /// Returns an object that can be used in a lock statement. Ex: lock(MySync.Lock(MyValue)) { ... }
    /// </summary>
    /// <param name="value"></param>
    /// <returns></returns>
    public SyncLock Lock(T value)
    {
        lock (mLock)
        {
            SyncLock theLock;
            if (mLocks.TryGetValue(value, out theLock))
                return theLock;

            theLock = new SyncLock(value, this);
            mLocks.Add(value, theLock);
            return theLock;
        }
    }

    /// <summary>
    /// Unlocks the object. Called from Lock.Dispose.
    /// </summary>
    /// <param name="theLock"></param>
    public void Unlock(SyncLock theLock)
    {
        mLocks.Remove(theLock.Value);
    }

    /// <summary>
    /// Represents a lock for the Synchronizer class.
    /// </summary>
    public class SyncLock
        : IDisposable
    {

        /// <summary>
        /// This class should only be instantiated from the Synchronizer class.
        /// </summary>
        /// <param name="value"></param>
        /// <param name="sync"></param>
        internal SyncLock(T value, Synchronizer<T> sync)
        {
            Value = value;
            Sync = sync;
        }

        /// <summary>
        /// Makes sure the lock is removed.
        /// </summary>
        public void Dispose()
        {
            Sync.Unlock(this);
        }

        /// <summary>
        /// Gets the value that this lock is based on.
        /// </summary>
        public T Value { get; private set; }

        /// <summary>
        /// Gets the synchronizer this lock was created from.
        /// </summary>
        private Synchronizer<T> Sync { get; set; }

    }

}
Run Code Online (Sandbox Code Playgroud)

这是你如何使用它...

public static readonly Synchronizer<int> sPostSync = new Synchronizer<int>();
....
using(var theLock = sPostSync.Lock(myID))
lock (theLock)
{
    ...
}
Run Code Online (Sandbox Code Playgroud)


Kon*_*lph 1

为什么不锁定整个帖子而只锁定其 ID?

  • 假设他有一些可以锁定的发布类(这将是很好的面向对象),但 id 可能只是数据库数据的输入参数,此时我猜锁应该在数据库级别,因此循环如果您可以完全锁定,针对发布实例执行此操作:) (2认同)