【问题标题】:should i lock local variable in multi-threading?我应该在多线程中锁定局部变量吗?
【发布时间】:2016-05-04 18:20:00
【问题描述】:

我正在 C# 中测试简单的缓存逻辑。这是我的 CacheManager 类:

public class CacheManager
{
    static List<string> _list = new List<string>();
    static readonly object _syncobject = new object();

    public static void ReloadList()
    {
        List<string> list = new List<string>();

        Random r = new Random();
        var count = r.Next(10);

        for (int i = 0; i < count; i++)
        {
            list.Add("list" + i);
        }

        //lock (_syncobject)
        {
            _list = list;
        }

    }


    public static IEnumerable<string> GetList()
    {
        //lock (_syncobject)
        {
            return _list;
        }
    }

}

下面是生成许多线程消耗 CacheManager 的类:

class Program
{
    static void Main(string[] args)
    {

        //threads for re-loading the list
        for (int i = 0; i < 3; i++)
        {
            Thread reloadThread = new Thread(ReloadList);
            reloadThread.Start();
        }

        //threads for getting the list
        for (int i = 0; i < 10; i++)
        {
            Thread tget = new Thread(PrintList);
            tget.Start();
        }

        //threads for getting the list and storing in local variable then use it
        for (int i = 0; i < 10; i++)
        {
            Thread tget = new Thread(PrintListWithLocalVariable);
            tget.Start();
        }

        Console.ReadKey();

    }

    private static void ReloadList()
    {
        do
        {
            Console.WriteLine("Reloading **********");
            CacheManager.ReloadList();

        } while (true);
    }

    private static void PrintList()
    {
        do
        {
            foreach (var item in CacheManager.GetList())
            {
                if (item == null)
                    throw new Exception("i == null");

                Console.WriteLine(item);
            }

        } while (true);
    }

    private static void PrintListWithLocalVariable()
    {
        do
        {
            var list = CacheManager.GetList();
            foreach (var listitem in list)
            {
                var i = list.FirstOrDefault(x => x.Equals(listitem));
                if (i == null)
                    throw new Exception("i == null");
                Console.WriteLine("Printing with Local variable:" + listitem);
            }

        } while (true);
    }


}

我的理解是我们应该在 CacheManager 中锁定 _list 变量,但看起来我们不需要那个。我将上述测试运行了一个小时左右,但没有出现任何错误。虽然 ReloadThread 正在重新加载随机数量的列表项,但其他线程正在循环列表中,我认为可能有问题。谁能解释一下为什么程序运行没有问题?

谢谢。

【问题讨论】:

标签: c# multithreading local-variables


【解决方案1】:

_list 是一个静态变量,这意味着CacheManager 的每个实例都将共享同一个_list 实例。确实应该锁定对_list 的访问以防止并发问题。正如评论中提到的那样,ConcurrentCollection 也应该用来代替 List(of T),因为 List(of T) 不是线程安全的。

【讨论】:

  • 事实上我在我的生产逻辑中添加了锁,但在此之前我正在测试它并且没有锁,逻辑运行了一段时间,这让我发布这个问题是否我错过了任何东西。 ConcurrentCollection 在这里可能没有用,因为我没有从列表中添加和获取项目。在 ReloadList 逻辑中,我只是用函数变量设置类变量。在返回时,我正在返回 IEnumerable,我相信它会为消费者创建一个副本。
  • 将返回类型设置为 IEnumerable(of T) 不会复制 _list。它只是将其作为派生较少的类型返回。如果您想要返回 _list 的副本,那么您可以将您的 getter 代码更改为 return _list.ToArray();,这将复制列表(但不复制其中的对象)。更好的做法可能是使用return _list.ToList().AsReadOnly(); 将其作为只读返回(ToList() 也会复制原始列表)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多