惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

S
SegmentFault 最新的问题
V
Vulnerabilities – Threatpost
博客园_首页
GbyAI
GbyAI
Martin Fowler
Martin Fowler
S
Secure Thoughts
Help Net Security
Help Net Security
Attack and Defense Labs
Attack and Defense Labs
大猫的无限游戏
大猫的无限游戏
量子位
腾讯CDC
博客园 - 叶小钗
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Microsoft Security Blog
Microsoft Security Blog
Cisco Talos Blog
Cisco Talos Blog
V
V2EX
P
Proofpoint News Feed
T
Tailwind CSS Blog
U
Unit 42
A
Arctic Wolf
PCI Perspectives
PCI Perspectives
B
Blog
F
Fortinet All Blogs
B
Blog RSS Feed
H
Hacker News: Front Page
P
Privacy & Cybersecurity Law Blog
Scott Helme
Scott Helme
G
GRAHAM CLULEY
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
H
Heimdal Security Blog
人人都是产品经理
人人都是产品经理
Forbes - Security
Forbes - Security
TaoSecurity Blog
TaoSecurity Blog
N
Netflix TechBlog - Medium
aimingoo的专栏
aimingoo的专栏
Security Archives - TechRepublic
Security Archives - TechRepublic
Y
Y Combinator Blog
Jina AI
Jina AI
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Latest news
Latest news
P
Privacy International News Feed
SecWiki News
SecWiki News
L
LINUX DO - 最新话题
M
MIT News - Artificial intelligence
W
WeLiveSecurity
博客园 - 聂微东
T
Tor Project blog
T
Troy Hunt's Blog
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Engineering at Meta
Engineering at Meta

博客园 - Kain

NET Reflector 7发布,其 不再免费 (抽象)工厂的另一种实现方式 自定义EF4 Model 代码生成 .net 4.0 中对多线程新特性(四)--任务和任务工厂 .net 4.0 中对多线程新特性(三) .net 4.0 中对多线程新特性(二) .net 4.0 中对多线程新特性(一) Flex&.Net开篇 SqlSever N层表数据查询效率 [读书笔记]Start-up fatigue(启动杂役) 马上又要过中秋和国庆了! 一个小问题 C#2.0 新的关键字 yield 我们的游戏! 不知道有没有同在学习aspnetforums的 郁闷! 关于面试 关于DataGride的Key事件 开心就好!
Microsoft.Practices.Unity 的一个线程安全Bug浅析
Kain · 2011-05-30 · via 博客园 - Kain

      从接触Enterprise Library开始,到现在越来越感觉的Elib的强大。虽然单独看Elib里面的Block不一定是优秀的,但是作为一个整体其优势不言而喻。更重要的是Elib是MS的团队在维护,不用担心MS会把它吃掉

      这段时间一直在Elib上进行开发,Unity也是用的最多的一个Block了。由于都是在单机开发BS系统,因此很少应用到多线程,多线程的问题也没有怎么暴露出来。以前也潜意识的认为MS会把线程安全处理好,但是今天发现其实不然。测试代码如下:

  1 class Program

 2     {
 3         static UnityContainer container;
 4         static bool stop;
 5         static void Main(string[] args)
 6         {
 7             container = new UnityContainer();
 8 
 9             var t1 = new Thread(new ThreadStart(Read));
10             var t2 = new Thread(new ThreadStart(Write));
11 
12             t1.Start();
13             t2.Start();
14 
15             Console.ReadLine();
16             stop = true;
17         }
18 
19         static void Read()
20         {
21             while (true)
22             {
23                 if (container.IsRegistered<int>("a"))
24                     Console.WriteLine("OK");
25                 Thread.Sleep(10);
26                 if (stop)
27                     break;
28             }
29         }
30 
31         static void Write()
32         {
33             int index = 0;
34             while (true)
35             {
36                 container.RegisterType<Program>(index.ToString());
37                 Console.WriteLine("Regist " + index);
38                 Thread.Sleep(10);
39                 index++;
40                 if (stop)
41                     break;
42             }
43         }
44     }

运行这个简单的sample,不久就会出现:Collection was modified; enumeration operation may not execute.异常,就是说在循环一个集合时,这个集合被另一线程修改了。这个错误在多线程编程中算比较经典的异常了。查看Unity的Regist方法的代码发现其实现其实非常简单。

   public static bool IsRegistered(this IUnityContainer container, Type typeToCheck, string nameToCheck)

        {
            Guard.ArgumentNotNull(container, 
"container");
            Guard.ArgumentNotNull(typeToCheck, 
"typeToCheck");

            var registration 

= from r in container.Registrations
                               
where r.RegisteredType == typeToCheck && r.Name == nameToCheck
                               select r;
            
return registration.FirstOrDefault() != null;
        }

 通过遍历一个Resitrations查找符合记录的条件。Registrations通过

 private void FillTypeRegistrationDictionary(IDictionary<Type, List<string>> typeRegistrations)
        {
            
if(parent != null)
            {
                parent.FillTypeRegistrationDictionary(typeRegistrations);
            }
foreach(Type t in registeredNames.RegisteredTypes)
            {
                
if(!typeRegistrations.ContainsKey(t))
                {
                    typeRegistrations[t] 
= new List<string>();
                }

                typeRegistrations[t] 

=
                    (typeRegistrations[t].Concat(registeredNames.GetKeys(t))).Distinct().ToList();
            }

        } 

 方法得到。到这里就可看到整个实现的核心所在:NamedTypesRegistry类型的registeredNames。这个类负责类型的注册,所有的注册信息都保存在这个类中。重点就在 public void RegisterType(Type t, string name)

        {
            
if(!registeredKeys.ContainsKey(t))
            {
                registeredKeys[t] 
= new List<string>();
            }

            RemoveMatchingKeys(t, name);
            registeredKeys[t].Add(name);
        }

 RegisterType方法,这个方法根本没有考虑到多线程同步问题直接对registeredKeys进行Add操作,同样在RegisteredTypes属性中也没有进行同步处理。很显然读写异步的情况肯定会出现上面所说的异常了。

虽然可以通过在外部调用Regist和IsRegist方法进行同步处理,但是这样的话调用外层的Lock就比较麻烦而且比较分散,性能也可能有问题。