zoukankan      html  css  js  c++  java
  • 【.NET深呼吸】存储基于本地线程的值

    在特定情况,我们希望这样一个场景:

    N个线程同时调用同一个类实例的同一个操作方法,并且同一个变量可以面向每一个线程存储独立的值。比如,某变量X,它对于线程A的值与对于线程B的值是相互独立的。线程A设置了X的值为3,那么只要代码是在线程A上执行的,那么变量X的值就是3;线程B设置X值为7,那么在线程B的代码中X的值就为7。

    同样一个X变量,不同的线程访问它就会读写不同的值

    有些时候,我们需要以上功能。只要把希望基于线程本地所使用的值的变量类型声明为ThreadLocal<T>类型即可,其中T表示该变量中要存储的值的数据类型。

    下面定义一个类:

        public sealed class ThreadingWork
        {
            private Random m_rand = null;
            private ThreadLocal<int> m_localVal = default(ThreadLocal<int>);
    
            public ThreadingWork()
            {
                m_rand = new Random();
                m_localVal = new ThreadLocal<int>();
            }
    
            private void MakeRandom()
            {
                m_localVal.Value = m_rand.Next(0, 1000);
            }
    
            public void RunOnThreads()
            {
                // 为变量生成值
                MakeRandom();
                // 引发事件
                string str = $"在线程{Thread.CurrentThread.ManagedThreadId}上设置的值为:{m_localVal.Value}";
                ThreadingRuned?.Invoke(this, new RunThreadEventArgs(str));
            }
    
            public event EventHandler<RunThreadEventArgs> ThreadingRuned;
            
        }
    
        /// <summary>
        /// 自定义事件参数类
        /// </summary>
        public class RunThreadEventArgs : EventArgs
        {
            internal RunThreadEventArgs(string s)
            {
                Value = s;
            }
    
            public string Value { get; private set; }
        }

    m_localVal变量是类的字段,它里面存放的是int类型的值。RunOnThreads方法会被不同的线程调用,线程执行方法后,会生成一个随机整数,并存到m_localVal变量中。接着引发ThreadingRuned事件,并将m_localVal变量中存放的值随着事件传递,以便被其他代码使用。

    下面,我们测试一下。

                // 实例化对象
                ThreadingWork work = new ThreadingWork();
                // 附加事件处理
                work.ThreadingRuned += Work_ThreadingRuned;
                // 创建30个Task来干活
                for(int n = 0; n < 30; n++)
                {
                    Thread t = new Thread(work.RunOnThreads);
                    t.Start();
                }

    上面代码创建了30个线程,并且线程所执行的都是同一个实例work上的RunOnThreads方法。

    当代码运行后,见证奇迹的一刻到了。

    从运行结果中可以发现,同一个实例方法被多个线程调用,但m_localVal变量可以存放来自各个线程的值,而每个线程所读取的都是基于当前线程的值,即每个线程读写的值都不同。

    尤其是在实现多线程下载的案例中,可以使用同一个实例变量来记录源自不同线程的下载进度(假设每个线程开启一个下载任务)。

    例子代码下载

  • 相关阅读:
    iOS-深入理解(转载)
    iOS开发
    夜光遥感
    希尔伯特曲线在地图图像分割中的应用
    希尔伯特曲线
    NLP生成论文
    MapGIS SDK(C++)【基础篇】
    从npm到vue和nodejs
    分形在遥感和GIS中的应用
    MapReduce、Hadoop、PostgreSQL、Spark
  • 原文地址:https://www.cnblogs.com/tcjiaan/p/4752189.html
Copyright © 2011-2022 走看看