繁体   English   中英

没有锁的Threadsafe集合

[英]Threadsafe collection without lock

我正准备接受采访,我遇到了跟​​随问题。 我试过,但我找不到任何可以创建包含线程安全集合而没有“锁定”的类。 如果知道任何解决方案,请帮助。

创建一个派生自Object的C#类,并实现以下方法:

  • AddString - 此方法应将给定字符串添加到内部集合
  • ToString - 重写此方法并返回包含内部集合中所有字符串的单个逗号分隔字符串

要求:

  • 必须是线程安全的
  • 必须支持多个并发读者
  • 不得使用任何预先存在的线程安全集合
  • 额外奖励:不要使用任何类型的锁

这是一种通过处理本地副本然后尝试在检查比赛时与全局集合进行原子交换来实现对集合的无锁修改的方法:

public class NonLockingCollection
{
    private List<string> collection;

    public NonLockingCollection()
    {
        // Initialize global collection through a volatile write.
        Interlocked.CompareExchange(ref collection, new List<string>(), null);
    }

    public void AddString(string s)
    {
        while (true)
        {
            // Volatile read of global collection.
            var original = Interlocked.CompareExchange(ref collection, null, null);

            // Add new string to a local copy.
            var copy = original.ToList();
            copy.Add(s);

            // Swap local copy with global collection,
            // unless outraced by another thread.
            var result = Interlocked.CompareExchange(ref collection, copy, original);
            if (result == original)
                break;
        }
    }

    public override string ToString()
    {
        // Volatile read of global collection.
        var original = Interlocked.CompareExchange(ref collection, null, null);

        // Since content of global collection will never be modified,
        // we may read it directly.
        return string.Join(",", original);
    }
}

编辑 :由于使用Interlocked.CompareExchange来隐式执行易失性读写会引起一些混乱,我在Thread.MemoryBarrier调用的等效代码下面发布。

public class NonLockingCollection
{
    private List<string> collection;

    public NonLockingCollection()
    {
        // Initialize global collection through a volatile write.
        collection = new List<string>();
        Thread.MemoryBarrier();
    }

    public void AddString(string s)
    {
        while (true)
        {
            // Fresh volatile read of global collection.
            Thread.MemoryBarrier();
            var original = collection;
            Thread.MemoryBarrier();

            // Add new string to a local copy.
            var copy = original.ToList();
            copy.Add(s);

            // Swap local copy with global collection,
            // unless outraced by another thread.
            var result = Interlocked.CompareExchange(ref collection, copy, original);
            if (result == original)
                break;
        }
    }

    public override string ToString()
    {
        // Fresh volatile read of global collection.
        Thread.MemoryBarrier();
        var original = collection;
        Thread.MemoryBarrier();

        // Since content of global collection will never be modified,
        // we may read it directly.
        return string.Join(",", original);
    }
}

您可以创建非阻止链接列表。 例如像这样的东西。

.net框架提供了像CompareExchange(Object, Object, Object)这样的方法,允许您编写安全代码而不锁定整个列表。

基于这个问题,您应该能够在对象中添加并发集合,以便为您处理线程安全要求。 他们没有指定要使用的内部集合类型。

您应该能够从concurrentcollection命名空间实现其中一个集合并实现此目的。

http://msdn.microsoft.com/en-us/library/system.collections.concurrent.aspx

我的解决方案 基本上使用Interlocked.Exchange和AutoResetEvents模仿锁定。 做了一些简单的测试,似乎有效。

    public class SharedStringClass
    {
        private static readonly int TRUE = 1;
        private static readonly int FALSE = 0;

        private static int allowEntry;

        private static AutoResetEvent autoResetEvent;

        private IList<string> internalCollection;

        public SharedStringClass()
        {
            internalCollection = new List<string>();
            autoResetEvent = new AutoResetEvent(false);
            allowEntry = TRUE;
        }

        public void AddString(string strToAdd)
        {
            CheckAllowEntry();

            internalCollection.Add(strToAdd);

            // set allowEntry to TRUE atomically
            Interlocked.Exchange(ref allowEntry, TRUE);
            autoResetEvent.Set();
        }

        public string ToString()
        {
            CheckAllowEntry();

            // access the shared resource
            string result = string.Join(",", internalCollection);

            // set allowEntry to TRUE atomically
            Interlocked.Exchange(ref allowEntry, TRUE);
            autoResetEvent.Set();
            return result;
        }

        private void CheckAllowEntry()
        {
            while (true)
            {
                // compare allowEntry with TRUE, if it is, set it to FALSE (these are done atomically!!)
                if (Interlocked.CompareExchange(ref allowEntry, FALSE, TRUE) == FALSE)
                {
                    autoResetEvent.WaitOne();
                }
                else
                {
                    break;
                }
            }
        }
    }

最简单的解决方案是使用string[]类型的字段。 每当调用者想要添加字符串时,创建一个附加了新项目的新数组,并将其替换为旧数组。

此模型不需要同步。 它不能容忍并发写入器,但它允许并发读取。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM