• C#线程安全使用(二)


    刚才想了半天文章应该起什么名字,最后决定起名为《线程安全使用》,线程安全这个词很难理解,感觉就像托管这词一样,但是托管翻译成英文是managed,我通常把他翻译成被管理,这样就好理解多了,线程安全也是一样,可以理解为可以被多个线程同时使用的集合,而且同时使用的时候是该集合的值是准确的。

    MSDN将在System.Collections.Concurrent命名空间下的集合,都称为线程安全的集合。

    下面举一个使用线程安全集合的例子,使用的是BlockingCollection,个人觉得这个集合是够用了,其他集合和这个集合基本上大同小异,没什么大区别。但是根据官方解释ConcurrentBag是适用于快速删除和添加,具体为什么他适用,而BlockingCollection不适用,我也没找到原因。

    using System;
    using System.Collections.Concurrent;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading;
    using System.Threading.Tasks;
    
    namespace ParallelConsole
    {
        class Program
        {
            
            //定义集合大小为51个,也可以不定义大小
            static BlockingCollection<int> blocking = new BlockingCollection<int>(51);
          
            static void Main(string[] args)
            {
                
    
                blocking = new BlockingCollection<int>();
                Console.WriteLine("当前blocking为:" + blocking.IsCompleted + "设置了集合大小count一样是0,blocking.Count:" + blocking.Count());
                //当前线程标识
                Console.WriteLine(Thread.CurrentThread.GetHashCode());
    
                for (int i = 0; i < 3; i++)
                {
                    ////如果添加到第3个,就设置添加完成,这时在添加就会抛异常
                    //if (i == 3)
                    //{
                    //    blocking.CompleteAdding();
                    //}
                  
                    Action<object> action = new Action<object>(run);
                    Task task = new Task(action,i); 
                    task.RunSynchronously(); 
                }
                Console.WriteLine("设置添加完成前:" + blocking.IsAddingCompleted);
                //设置添加完成后
                blocking.CompleteAdding();
                Console.WriteLine("设置添加完成后:" + blocking.IsAddingCompleted);
                #region 同步取 取3个
                //for (int i = 0; i < 3; i++)
                //{
                //    Action actionTake = new Action(take);
                //    actionTake();
                //}
                #endregion
                //并发读取
                
                #region 并发步取 取3个
                //blocking.IsCompleted 只有当集合被添加进内容,然后又都被取光了以后,他才会等于ture,否则都是false
                //当IsCompleted为ture时,就不能再取了否则会抛异常
                
                //同时取,结果是 
                //blocking:0
                //blocking:2
                //blocking:1
                if (!blocking.IsCompleted)//如果集合没取光
                {
                    Action actionTake2 = new Action(take);
                    Parallel.Invoke(actionTake2, actionTake2, actionTake2);
                }
                #endregion
    
                Console.WriteLine("当前blocking为:" + blocking.IsCompleted +  ",blocking数量为:" + blocking.Count());
                //数据被取光了以后, blocking.Count()为0
                Console.Read();
            }
    
            public static void take()
            {
                //同步取,blocking.Count()会真实的表现,而异步取,Count是不准确的,因为我取count的时候,可能集合已经又被取出数据了,测试10次肯定会出现不真实的情况
                Console.WriteLine("blocking:" + blocking.Take() + ",blocking数量为:" + blocking.Count());
            }
            public static void run(object i)
            {
                int currentI = int.Parse(i.ToString());
                blocking.TryAdd(currentI); 
            }
        }
    }
    View Code

    解释几个方法:

     Parallel.Invoke(),并发调用ACtion,可以传多个action,也可以传一个action数据组。

     Task(action<t>,object),这是Task的构造方法,接受action,注意object是action的参数,但是解释中并没有说的很明白。(翻译坑,你懂的),根据MSDN提供的构造方法,并没有接受action<t,t>,action<t,t,t>这样的,也就是说,定义函数时,要传递一个实体,而不要传递多个参数,否则任务调用不了。

     task.RunSynchronously(),根据MSDN解释,他是同步运行任务计划用的,同时他和task.Start()一样,也可以启动线程。

    BlockingCollection集合

    属性一:IsCompleted,他是表示集合是否有数据,只有当集合被添加进内容,然后又都被取光了以后,他才会等于ture,否则都是false。

    PS:这个解释如果你要看MSDN一辈子都想不明白,msdn的中文翻译真心坑。

    属性一:BlockingCollection.IsAddingCompleted,表示是否添加完成。针对blocking.CompleteAdding()的使用,当调用了该方法IsAddingCompleted就为true。

    方法一:BlockingCollection.blocking.CompleteAdding(),设置IsAddingCompleted用的。

    方法二:BlockingCollection.Add,添加一个实体

    方法三:BlockingCollection.TryAdd,添加一个实体,我这里用的是这个方法,区别是,如果添加重复项,他会引发InvalidOperationException这个异常。

    方法四:BlockingCollection.Take,从集合中取一个值,注意,是真的取出来,取出来后,BlockingCollection.cout会减一。

    运行结果如下:

    今天先写到这,写文字还真是累,明明没写几个字。。。

    ----------------------------------------------------------------------------------------------------

    注:此文章为原创,任何形式的转载都请联系作者获得授权并注明出处!
    若您觉得这篇文章还不错,请点击下方的推荐】,非常感谢!

     

    https://www.cnblogs.com/kiba/
  • 相关阅读:
    git 简单操作
    总结vue 需要掌握的知识点
    windows10为何鼠标右键失灵,桌面右键一直转圈的解决
    maven项目(引入依赖失败, pom.xml 报错\爆红)
    word 选中后背景是黑色的
    Excel数字转日期
    冯况 | 删除文件显示【需要来自system的权限】
    拖动东西时垫纸减少摩擦
    妙用瑜伽垫
    不用电磁炉了
  • 原文地址:https://www.cnblogs.com/kiba/p/3375568.html
Copyright © 2020-2023  润新知