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

推荐订阅源

D
Docker
Simon Willison's Weblog
Simon Willison's Weblog
H
Help Net Security
F
Fortinet All Blogs
H
Heimdal Security Blog
S
Schneier on Security
L
LangChain Blog
博客园 - Franky
酷 壳 – CoolShell
酷 壳 – CoolShell
NISL@THU
NISL@THU
P
Palo Alto Networks Blog
J
Java Code Geeks
博客园 - 【当耐特】
The Last Watchdog
The Last Watchdog
W
WeLiveSecurity
www.infosecurity-magazine.com
www.infosecurity-magazine.com
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
V
Vulnerabilities – Threatpost
I
InfoQ
Recorded Future
Recorded Future
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
C
CERT Recently Published Vulnerability Notes
T
Tenable Blog
腾讯CDC
C
Check Point Blog
量子位
M
MIT News - Artificial intelligence
GbyAI
GbyAI
罗磊的独立博客
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
B
Blog
小众软件
小众软件
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
C
CXSECURITY Database RSS Feed - CXSecurity.com
Stack Overflow Blog
Stack Overflow Blog
P
Proofpoint News Feed
P
Privacy & Cybersecurity Law Blog
V2EX - 技术
V2EX - 技术
T
Threatpost
Engineering at Meta
Engineering at Meta
Attack and Defense Labs
Attack and Defense Labs
T
Tailwind CSS Blog
S
Securelist
The Cloudflare Blog
博客园 - 叶小钗
L
LINUX DO - 最新话题
T
Troy Hunt's Blog
C
Cyber Attacks, Cyber Crime and Cyber Security
爱范儿
爱范儿

博客园 - Henry Cui

招聘高级.Net工程师 Node.js Web开发(二)认识Express(上) Node.js Web开发(一)从零开始 Html5 Step by Step(二) 本地存储 HTML 5 Step by Step(一) 拖放API Git学习笔记(一)初识Git DDD中的Specification模式 Silverlight 4之旅(三)数据绑定(中) Silverlight 4之旅(二)数据绑定(上) Silverlight 4之旅(一) .Net 4.0 Parallel 编程之旅 .Net 4.0 Parallel编程(八)Task中的数据共享(中) .Net 4.0 Parallel 编程(七)Task中的数据共享(上) .Net 4.0 Parallel 编程(六)Task(下) .Net 4.0 Parallel 编程(五)Task(中) .Net 4.0 Parallel 编程(四) Task(上) Entity Framework Code-First(下) Entity Framework Code-First(上) Entity Framework POCO T4模板使用
.Net 4.0 Parallel 编程(九)Task中的数据共享(下)
Henry Cui · 2011-04-21 · via 博客园 - Henry Cui

2011-04-21 10:17  Henry Cui  阅读(3025)  评论()    收藏  举报

在上篇Post中我们看过了几种常用的同步类型,本篇文章会介绍下申明性的同步的实现以及对于集合类型数据共享的问题,首先看下申明性同步的实现。

申明性同步

我们可以通过使用Synchronization 特性来标识一个类,从而使一个类型的字段以及方法都实现同步化。在使用Synchronization 时,我们需要将我们的目标同步的类继承于System.ContextBoundObject类型。我们来看看之前的例子我们同步标识Synchronization 的实现:

[Synchronization]
class SumClass : ContextBoundObject
{
    private int _Sum;

    public void Increment()
    {
        _Sum++;
    }

    public int GetSum()
    {
        return _Sum;
    }
}
class Program
{
    static void Main(string[] args)
    {
        var sum = new SumClass();
        Task[] tasks = new Task[10];
        for (int i = 0; i < 10; i++)
        {
            tasks[i] = new Task(() =>
            {
                for (int j = 0; j < 1000; j++)
                {
                    sum.Increment();
                }
            });
            tasks[i].Start();
        }
        Task.WaitAll(tasks);
        Console.WriteLine("Expected value {0}, Parallel value: {1}",
        10000, sum.GetSum());
        Console.ReadLine();
    }
}

并发集合

在某些时候我们需要并发的操作集合类型,对于集合类型也存在数据共享的问题,我们来看一个例子,在例子中我们创建一个队列,然后多个Task同步进行出队列操作,看会不会出现同步出一个元素的情况,其中我们通过一个计数器进行统计出队列的次数:

static void Main(string[] args)
{
    for (var j = 0; j < 10; j++)
    {
        var queue = new Queue<int>();
        var count = 0;
        for (var i = 0; i < 1000; i++)
        {
            queue.Enqueue(i);
        }
        var tasks = new Task[10];
        for (var i = 0; i < tasks.Length; i++)
        {
            tasks[i] = new Task(() =>
            {
                while (queue.Count > 0)
                {
                    var item = queue.Dequeue();
                    Interlocked.Increment(ref count);
                }
            });
            tasks[i].Start();
        }
        try
        {
            Task.WaitAll(tasks);
        }
        catch (AggregateException e)
        {
            e.Handle((ex) =>
            {
                Console.WriteLine("Exception Message:{0}",ex.Message);
                return true;
            });
        }
        Console.WriteLine("Dequeue items count :{0}", count);
    }
    Console.ReadKey();
}

在上面的示例中,我们为了让效果更佳明显,看十次运行的结果:

image

在上面我们看到两个问题:1.出队列的次数超过了1000个;2.出现异常消息已经为空。出现这两个异常的原因是:1.多个线程同时在操作一个元素进行出的动作;2消息为空是因为当队列中剩下最后一个元素时,某个线程在访问“queue.Count > 0”时确实是大于0的,所以进入循环代码中准备进行出队列动作,而另外一个线程也进入循环中,已经将队列中出完了,就出现了数据争用的情况。

在.Net 4.0中提供了很多并发的集合类型来让我们处理数据同步的集合的问题,这里面包括:

1.ConcurrentQueue:提供并发安全的队列集合,以先进先出的方式进行操作;

2.ConcurrentStack:提供并发安全的堆栈集合,以先进后出的方式进行操作;

3.ConcurrentBag:提供并发安全的一种特殊的排序的集合;

4.ConcurrentDictionary:提供并发安全的一种key-value类型的集合。

我们在这里只做ConcurrentQueue的一个尝试,并发队列是一种线程安全的队列集合,我们可以通过Enqueue()进行排队、TryDequeue()进行出队列操作,在上面的例子中我们使用ConcurrentQueue时:

static void Main(string[] args)
{
    for (var j = 0; j < 10; j++)
    {
        var queue = new ConcurrentQueue<int>();
        var count = 0;
        for (var i = 0; i < 1000; i++)
        {
            queue.Enqueue(i);
        }
        var tasks = new Task[10];
        for (var i = 0; i < tasks.Length; i++)
        {
            tasks[i] = new Task(() =>
            {
                while (queue.Count > 0)
                {
                    int item;
                    var isDequeue = queue.TryDequeue(out item);
                    if(isDequeue) Interlocked.Increment(ref count);
                }
            });
            tasks[i].Start();
        }
        try
        {
            Task.WaitAll(tasks);
        }
        catch (AggregateException e)
        {
            e.Handle((ex) =>
            {
                Console.WriteLine("Exception Message:{0}",ex.Message);
                return true;
            });
        }
        Console.WriteLine("Dequeue items count :{0}", count);
    }
    Console.ReadKey();
}

总结

在本文中看过了数据共享中如何使用Synchronization 进行申明性同步,以及同步集合的一些介绍,希望对您有帮助。到此,Task中的数据共享就介绍结束了,下面我们看下PLinq中的内容。

alt