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

推荐订阅源

酷 壳 – CoolShell
酷 壳 – CoolShell
H
Hacker News: Front Page
P
Palo Alto Networks Blog
T
ThreatConnect
Apple Machine Learning Research
Apple Machine Learning Research
博客园_首页
T
True Tiger Recordings
P
Privacy & Cybersecurity Law Blog
B
Blog
IT之家
IT之家
Last Week in AI
Last Week in AI
F
Full Disclosure
Hacker News: Ask HN
Hacker News: Ask HN
C
Comments on: Blog
Microsoft Azure Blog
Microsoft Azure Blog
C
Cybersecurity and Infrastructure Security Agency CISA
Microsoft Security Blog
Microsoft Security Blog
博客园 - 【当耐特】
N
News and Events Feed by Topic
NISL@THU
NISL@THU
腾讯CDC
雷峰网
雷峰网
Security Latest
Security Latest
李成银的技术随笔
M
Microsoft Research Blog - Microsoft Research
L
LangChain Blog
L
Lohrmann on Cybersecurity
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
C
Check Point Blog
Y
Y Combinator Blog
Recent Announcements
Recent Announcements
博客园 - Franky
N
News | PayPal Newsroom
V
V2EX
A
About on SuperTechFans
The Register - Security
The Register - Security
月光博客
月光博客
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Google Online Security Blog
Google Online Security Blog
MyScale Blog
MyScale Blog
Cisco Talos Blog
Cisco Talos Blog
Vercel News
Vercel News
WordPress大学
WordPress大学
C
Cyber Attacks, Cyber Crime and Cyber Security
The Hacker News
The Hacker News
IntelliJ IDEA : IntelliJ IDEA – the Leading IDE for Professional Development in Java and Kotlin | The JetBrains Blog
IntelliJ IDEA : IntelliJ IDEA – the Leading IDE for Professional Development in Java and Kotlin | The JetBrains Blog
爱范儿
爱范儿
A
Arctic Wolf
L
LINUX DO - 最新话题
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More

博客园 - Kain

NET Reflector 7发布,其 不再免费 (抽象)工厂的另一种实现方式 自定义EF4 Model 代码生成 - Kain .net 4.0 中对多线程新特性(四)--任务和任务工厂 .net 4.0 中对多线程新特性(三) .net 4.0 中对多线程新特性(二) .net 4.0 中对多线程新特性(一) Flex&.Net开篇 - Kain 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就比较麻烦而且比较分散,性能也可能有问题。