• 集合类的线程安全


    在.Net Framework 4.0之前,为解决集合的安全问题,主要用到的方法是锁。举一个例子。假若计算机的某一个文件夹中存在1000张图片,现在要对这1000张图片做缩略图处理,把处理好的缩略图保存到另外一个文件夹中。

    先写一个处理图片缩略图的类,代码图下所示:

      
       public class OperPicClass
        {
            /// <summary>
            /// 输入jpg文件
            /// </summary>
            public string InFileName { get; set; }
            /// <summary>
            /// 输出jpg缩略图的文件
            /// </summary>
            public string OutFileName { get; set; }
            public OperPicClass()
            {
                
            }
            /// <summary>
            /// 处理缩略图
            /// </summary>
            /// <returns></returns>
            public bool Exc()
            {
                //string pDir = System.IO.Path.GetDirectoryName(OutFileName);
                //if (!System.IO.Directory.Exists(pDir))
                //{
                //    System.IO.Directory.CreateDirectory(pDir);
                //}
                Console.WriteLine("处理图片:" + Thread.CurrentThread.Name + "||" + InFileName);
                return true;
            }
        }

    单线程情况下,对1000张图片的处理如下:

          
    private void btRun_Click(object sender, EventArgs e)
            {
                //单线程下,图片生成缩略图             
                List<OperPicClass> listJpgFiles = new List<OperPicClass>();
                for (int i = 0; i < 1000; i++)
                {
                    listJpgFiles.Add(new OperPicClass() { InFileName = "文件路径", OutFileName = "输出路径" });
                }
                listJpgFiles.ForEach((o) => { o.Exc(); });
            }

    单线程下,会导致1000张图片处理时间长。分析1000张图片做缩略图,整个过程互不干扰,考虑用多线程的方式,减少处理时间。在.Net Framework 4.0出现之前,为了保证集合安全,需要重写一个安全的集合类,如下所示:

       
        public class MutilThreadOperClass<T> : List<T> where T : new()
        {
    
            private readonly object _lock;
            public MutilThreadOperClass()
            {
                _lock = new object();
            }
            public new void Add(T t)
            {
                lock (_lock)
                {
                    base.Add(t);
                }
            }
            private int _index = 0;
            public T getObject()
            {
                T t = default(T);
                if (_index >= 0 && _index < this.Count)
                {
                    lock (_lock)
                    {
                        t = this[_index];
                        _index++;
                    }
                }
                return t;
            }
        }

    集合类写好后,多线程处理如下所示:

    private void btRun_Click(object sender, EventArgs e)
            {
                MutilThreadOperClass<OperPicClass> tMutilThreadOperClass = new MutilThreadOperClass<OperPicClass>();
                for (int i = 0; i < 10000; i++)
                {
                    tMutilThreadOperClass.Add(new OperPicClass() { InFileName = "文件路径" + i, OutFileName = "输出路径" });
                }
                Thread[] tThread = new Thread[8];
                for (int i = 0; i < tThread.Length; i++)
                {
                    tThread[i] = new Thread(() =>
                        {
                            while (true)
                            {
                                Thread.Sleep(10);
                                try
                                {
                                    OperPicClass d = tMutilThreadOperClass.getObject();
                                    d.Exc();
                                }
                                catch
                                { break; }
                            }
                        });
                    tThread[i].IsBackground = true;
                    tThread[i].Name = "我是线程" + i;
                    tThread[i].Start();
                }
            }
           

    .Net Framework 4.0出现之后,微软提供了System.Collections.Concurrent命名空间,在此命名空间中,有以下类:

     类说明
    公共类 BlockingCollection<T> 为实现 IProducerConsumerCollection<T> 的线程安全集合提供阻塞和限制功能。
    公共类 ConcurrentBag<T> 表示对象的线程安全的无序集合。
    公共类 ConcurrentDictionary<TKey, TValue> 表示可由多个线程同时访问的键值对的线程安全集合。
    公共类 ConcurrentQueue<T> 表示线程安全的先进先出 (FIFO) 集合。
    公共类 ConcurrentStack<T> 表示线程安全的后进先出 (LIFO) 集合。
    公共类 OrderablePartitioner<TSource> 表示将一个可排序数据源拆分成多个分区的特定方式。
    公共类 Partitioner 提供针对数组、列表和可枚举项的常见分区策略。
    公共类 Partitioner<TSource> 表示将一个数据源拆分成多个分区的特定方式。

    其中,经常用到是ConcurrentBag<T>ConcurrentQueue<T>ConcurrentDictionary<TKey, TValue>。以ConcurrentBag<T>为例。实现上面的过程。首先用它的优点就是不需要再额外写MutilThreadOperClass这个类了。也可以理解为微软用ConcurrentBag<T>代替了自己写的这个安全类。其次就是线程安全,可以自由访问集合中的要素了。代码如下:

            private void btRun_Click(object sender, EventArgs e)
            {
                System.Collections.Concurrent.ConcurrentBag<OperPicClass> tConcurrentBag = new System.Collections.Concurrent.ConcurrentBag<OperPicClass>();
                for (int i = 0; i < 10000; i++)
                {
                    tConcurrentBag.Add(new OperPicClass() { InFileName = "文件路径" + i, OutFileName = "输出路径" });
                }
                Thread[] tThread = new Thread[8];
                for (int i = 0; i < tThread.Length; i++)
                {
                    tThread[i] = new Thread(() =>
                    {
                        OperPicClass d;
                        while (tConcurrentBag.TryTake(out d))//TryTake方法与TryPeek方法的区别在于是否移除元素。
                        {
                            Thread.Sleep(10);
                            d.Exc();
                        }
                    });
                    tThread[i].IsBackground = true;
                    tThread[i].Name = "我是线程" + i;
                    tThread[i].Start();
                }
            }
           
  • 相关阅读:
    VS.NET2013发布网站的时候去掉.cs文件(预编译)(转)
    vs2013发布网站合并程序是出错(ILmerge.merge:error)
    转:c# Linq 的分页[转]
    AStar 路径规划之初级二
    ASttar 路径规划之初级
    AttributeError: module 'tensorflow' has no attribute 'set_random_seed'
    github提示Permission denied (publickey),如何才能解决?
    机器学习-模型评价指标
    pcl-qt使用QVTKWidget 与PCLVisualizer 显示雷达点云
    pcl-设置多线段宽度和颜色
  • 原文地址:https://www.cnblogs.com/cglNet/p/6370813.html
Copyright © 2020-2023  润新知