在同一方法中写入两个 .net 字典时的线程安全

发布于 2024-12-01 11:57:44 字数 1687 浏览 1 评论 0原文

我被要求使类内的字典线程安全。

我的第一个建议是实现一个线程安全字典,.net 开发人员社区已经致力于此,但被拒绝了。

代码是这样的:

class Example()
{
    Dictionary<string, string> dic1;
    Dictionary<string, string> dic2;
     public void Example()
     {
        dic1 = new Dictionary<string,string>(10);
        dic2 = new Dictionary<string,string>(10);
     }

     public string Method1(string param1)
     {
            if(dic1.ContainsKey(param1))
            {
                return dic1[param1];
            }

            if(IsValidParam(param1))
            {
                dic1.Add(param1, param1);
                return param1;
            }

            try
            {   
                var params = GetValidParams(param1);
                if(params.Count > 0)
                {
                    foreach(var param in params)
                    {
                        if(!isValirParam(param)
                            continue;

                        dic1.Add(param1, param);

                        if(!dic2.ContainsKey(param1))
                        {
                            dic2.Add(param, param1);
                        }

                        return param;
                    }
                }
                else
                {
                    dic2.Add(param1, param1);
                    return param1;
                }
            }
            catch(Exception ex)
            {
                .....
            }

            return param1;
     }
}

这只是对同一方法内的两个字典具有读写访问权限的众多方法之一。

我正在考虑重构并在每个添加和返回中使用“ReaderWriterLockSlim”,但我不知道这是否会使该线程安全。

您知道如何解决这个问题吗?我愿意接受建议...

提前感谢您的宝贵时间

I've been asked to make dictionaries inside a class thread safe.

My first proposal was to implement a thread safe dictionary, the community of .net developers had already worked on that but it was rejected.

The code is something like this:

class Example()
{
    Dictionary<string, string> dic1;
    Dictionary<string, string> dic2;
     public void Example()
     {
        dic1 = new Dictionary<string,string>(10);
        dic2 = new Dictionary<string,string>(10);
     }

     public string Method1(string param1)
     {
            if(dic1.ContainsKey(param1))
            {
                return dic1[param1];
            }

            if(IsValidParam(param1))
            {
                dic1.Add(param1, param1);
                return param1;
            }

            try
            {   
                var params = GetValidParams(param1);
                if(params.Count > 0)
                {
                    foreach(var param in params)
                    {
                        if(!isValirParam(param)
                            continue;

                        dic1.Add(param1, param);

                        if(!dic2.ContainsKey(param1))
                        {
                            dic2.Add(param, param1);
                        }

                        return param;
                    }
                }
                else
                {
                    dic2.Add(param1, param1);
                    return param1;
                }
            }
            catch(Exception ex)
            {
                .....
            }

            return param1;
     }
}

This is only one of the many methods that have read and write access to both of the dictionaries inside the same method.

I was thinking on refactoring and use "ReaderWriterLockSlim" in each Add and return, but I don't know if this is going to make this thread safe.

Do you have any idea how to approach this? I'm open to suggestions...

Thanks in advance for your time

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

冷…雨湿花 2024-12-08 11:57:44

在这种情况下,确保您获得预期结果的最简单方法是使用

class Example()
{
    Dictionary<string, string> dic1;
    Dictionary<string, string> dic2;
    private Object syncRoot;
     public void Example()
     {
        dic1 = new Dictionary<string,string>(10);
        dic2 = new Dictionary<string,string>(10);
        syncRoot = new Object();
     }

     public string Method1(string param1)
     {
         lock(syncRoot) {
            if(dic1.ContainsKey(param1))
            {
                return dic1[param1];
            }

            if(IsValidParam(param1))
            {
                dic1.Add(param1, param1);
                return param1;
            }

            try
            {   
                var params = GetValidParams(param1);
                if(params.Count > 0)
                {
                    foreach(var param in params)
                    {
                        if(!isValirParam(param)
                            continue;

                        dic1.Add(param1, param);

                        if(!dic2.ContainsKey(param1))
                        {
                            dic2.Add(param, param1);
                        }

                        return param;
                    }
                }
                else
                {
                    dic2.Add(param1, param1);
                    return param1;
                }
            }
            catch(Exception ex)
            {
                .....
            }

            return param1;
          }
     }
}

请注意,这会使事情变慢(锁有一些开销,特别是您不会有两个线程同时在锁定块内执行任何操作),但它确保运行此方法的 Thread2 无法更改Thread1 测试某个值与尝试使用该测试的结果执行某些操作之间的时间。它也不需要 .net 4,因此您将能够使用它。

编辑 - 还值得一提的是,如果您有任何其他方法可以修改任一字典,您将需要以相同的方式锁定它们。这里的关键是,在任何给定的时刻,只有一个线程可以搞乱东西。

The simplest way in this case to ensure that you're going to get what you expect is to use a lock.

class Example()
{
    Dictionary<string, string> dic1;
    Dictionary<string, string> dic2;
    private Object syncRoot;
     public void Example()
     {
        dic1 = new Dictionary<string,string>(10);
        dic2 = new Dictionary<string,string>(10);
        syncRoot = new Object();
     }

     public string Method1(string param1)
     {
         lock(syncRoot) {
            if(dic1.ContainsKey(param1))
            {
                return dic1[param1];
            }

            if(IsValidParam(param1))
            {
                dic1.Add(param1, param1);
                return param1;
            }

            try
            {   
                var params = GetValidParams(param1);
                if(params.Count > 0)
                {
                    foreach(var param in params)
                    {
                        if(!isValirParam(param)
                            continue;

                        dic1.Add(param1, param);

                        if(!dic2.ContainsKey(param1))
                        {
                            dic2.Add(param, param1);
                        }

                        return param;
                    }
                }
                else
                {
                    dic2.Add(param1, param1);
                    return param1;
                }
            }
            catch(Exception ex)
            {
                .....
            }

            return param1;
          }
     }
}

Note that this will make things slower (lock has some overhead and in particular you won't have two threads executing anything inside the lock'd block at the same time), but it ensures that Thread2 running this method can't change something in between when Thread1 tested a value and when it then tries to use the result of that test to do something. It also doesn't require .net 4, so you'll be able to use it.

edit - It's also worth mentioning that if you have any other methods that modify either dictionary, you'll want to lock them the same way. The key thing here is that only one thread can be messing around with stuff at any given moment of time.

-残月青衣踏尘吟 2024-12-08 11:57:44

在 .NET 4 上已经有 ConcurrentDictionary

On .NET 4 there is already ConcurrentDictionary<T,V>.

红墙和绿瓦 2024-12-08 11:57:44

就像 Tridus说您几乎必须将 Method1 的全部内容包装在 lock 中。然而,这可能是 ReaderWriterLockSlim 真正有帮助的一种情况。您可以对 dic1 中的初始查找进行读锁定。如果成功,那么您就可以退出而无需获取独占写锁。如果查找失败,则升级到写锁。当然,您必须进行测试,但如果预计初始查找在大多数情况下都会成功,那么您可以获得大量并发性。

Like Tridus said you are pretty much going to have to wrap the entire contents of Method1 in a lock. However, this may be one scenario where ReaderWriterLockSlim might actually help. You could take a read lock on the initial lookup in dic1. If it succeeds then you can bail out without ever taking the exclusive write lock. If the lookup fails then you upgrade to a write lock. You would have to test of course, but if the initial lookup is expected to succeed most of the time then you could gain a lot of concurrency.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文