Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
.net CallContext.SetData()-当线程处于活动状态(TPL)时,对象是否可用?_.net_.net 3.5_.net 4.0_Task Parallel Library - Fatal编程技术网

.net CallContext.SetData()-当线程处于活动状态(TPL)时,对象是否可用?

.net CallContext.SetData()-当线程处于活动状态(TPL)时,对象是否可用?,.net,.net-3.5,.net-4.0,task-parallel-library,.net,.net 3.5,.net 4.0,Task Parallel Library,各位 假设我使用线程10、11、12中的CallContext.SetData()存储对象Car的三个新实例。这些线程完成执行。然后我执行另一个多线程操作(可能与第一个操作不同),它使用线程10、11、12。GetData()是否会检索与我存储的三个对象相同的对象?或者是现在的环境不同了,那些物体消失了 我的特定用例是任务并行库。我正在使用TPL并行化一些操作,我想了解TPL调用之间通过CallContext.SetData()存储的数据会发生什么情况 编辑 根据@wageoghe的建议,我尝试

各位

假设我使用线程10、11、12中的CallContext.SetData()存储对象Car的三个新实例。这些线程完成执行。然后我执行另一个多线程操作(可能与第一个操作不同),它使用线程10、11、12。GetData()是否会检索与我存储的三个对象相同的对象?或者是现在的环境不同了,那些物体消失了

我的特定用例是任务并行库。我正在使用TPL并行化一些操作,我想了解TPL调用之间通过CallContext.SetData()存储的数据会发生什么情况

编辑
根据@wageoghe的建议,我尝试了ThreadLocal,效果很好

更新代码以证明这一点:

using System;
using System.Threading;
using System.Threading.Tasks;

namespace TlsTest
{

    public class Program
    {

        public static void Main()
        {
            Console.WriteLine( "-------using threadpool---------" );
            UseThreadPool();
            Console.WriteLine( "-------using tasks---------" );
            UseTasks();
            Console.WriteLine( "-------using parallel for---------" );
            UseParallelFor();
            Console.ReadKey();
        }

        public static void UseThreadPool()
        {

            var finish = new CountdownEvent( TotalThreads );

            for ( int i = 0 ; i < TotalThreads ; i++ )
            {
                ThreadPool.QueueUserWorkItem( x =>
                {
                    int id = Thread.CurrentThread.ManagedThreadId;

                    Thread.Sleep( SleepMilliseconds );

                    if ( ThreadId.IsValueCreated )
                    {
                        Console.WriteLine( "thread [{0}], tls.thread [{1}] - value already in Tls" , id , ThreadId.Value );                        
                    }
                    else
                    {                        
                        Console.WriteLine( "thread [{0}] - no Tls value" , id );
                        ThreadId.Value = id;
                    }
                    Thread.Sleep( SleepMilliseconds );
                    finish.Signal();
                } );
            }
            finish.Wait();
        }

        public static void UseTasks()
        {
            const TaskCreationOptions taskCreationOpt = TaskCreationOptions.None;

            var allTasks = new Task[ TotalThreads ];
            for ( int i = 0 ; i < TotalThreads ; i++ )
            {
                Task task = Task.Factory.StartNew( () =>
                {
                    int id = Thread.CurrentThread.ManagedThreadId;

                    Thread.Sleep( SleepMilliseconds );

                    if ( ThreadId.IsValueCreated )
                    {
                        Console.WriteLine( "thread [{0}], tls.thread [{1}] - value already in Tls" , id , ThreadId.Value );
                    }
                    else
                    {
                        Console.WriteLine( "thread [{0}] - no Tls value" , id );
                        ThreadId.Value = id;                        
                    }

                    Thread.Sleep( SleepMilliseconds );

                } , taskCreationOpt );
                allTasks[ i ] = task;
            }
            Task.WaitAll( allTasks );
        }

        public static void UseParallelFor()
        {

            var options = new ParallelOptions();
            options.MaxDegreeOfParallelism = 8;
            Parallel.For( 0 , TotalThreads , options , i =>
            {
                int id = Thread.CurrentThread.ManagedThreadId;

                Thread.Sleep( SleepMilliseconds );

                if ( ThreadId.IsValueCreated )
                {
                    Console.WriteLine( "thread [{0}], tls.thread [{1}] - value already in Tls" , id , ThreadId.Value );
                }
                else
                {
                    Console.WriteLine( "thread [{0}] - no Tls value" , id );
                    ThreadId.Value = id;                                        
                }

                Thread.Sleep( SleepMilliseconds );

            } );            
        }

        private static readonly ThreadLocal<int> ThreadId = new ThreadLocal<int>();
        private const int TotalThreads = 100;
        private const int SleepMilliseconds = 500;

    }    
}
使用系统;
使用系统线程;
使用System.Threading.Tasks;
名称空间TlsTest
{
公共课程
{
公共静态void Main()
{
Console.WriteLine(“----使用线程池----”;
使用线程池();
Console.WriteLine(“----使用任务---------”);
使用任务();
Console.WriteLine(“----使用parallel表示----”;
UseParallelFor();
Console.ReadKey();
}
公共静态void UseThreadPool()
{
var finish=新的倒计时事件(TotalThreads);
对于(inti=0;i
{
int id=Thread.CurrentThread.ManagedThreadId;
睡眠(睡眠毫秒);
if(ThreadId.IsValueCreated)
{
WriteLine(“thread[{0}],tls.thread[{1}]-值已在tls中”,id,ThreadId.value);
}
其他的
{                        
WriteLine(“线程[{0}]-没有Tls值”,id);
ThreadId.Value=id;
}
睡眠(睡眠毫秒);
完成。信号();
} );
}
完成。等待();
}
公共静态任务()
{
const TaskCreationOptions taskCreationOpt=TaskCreationOptions.None;
var allTasks=新任务[TotalThreads];
对于(inti=0;i
{
int id=Thread.CurrentThread.ManagedThreadId;
睡眠(睡眠毫秒);
if(ThreadId.IsValueCreated)
{
WriteLine(“thread[{0}],tls.thread[{1}]-值已在tls中”,id,ThreadId.value);
}
其他的
{
WriteLine(“线程[{0}]-没有Tls值”,id);
ThreadId.Value=id;
}
睡眠(睡眠毫秒);
},taskCreationOpt);
所有任务[i]=任务;
}
Task.WaitAll(所有任务);
}
用于()的公共静态void
{
var options=新的ParallelOptions();
options.MaxDegreeOfParallelism=8;
对于(0,TotalThreads,options,i=>
{
int id=Thread.CurrentThread.ManagedThreadId;
睡眠(睡眠毫秒);
if(ThreadId.IsValueCreated)
{
WriteLine(“thread[{0}],tls.thread[{1}]-值已在tls中”,id,ThreadId.value);
}
其他的
{
WriteLine(“线程[{0}]-没有Tls值”,id);
ThreadId.Value=id;
}
睡眠(睡眠毫秒);
} );            
}
private static readonly ThreadLocal ThreadId=new ThreadLocal();
private const int TotalThreads=100;
私有常量int=500;
}    
}

[更新]

事实上,我最初的答案(在这篇文章的底部)似乎有一部分是错的

我编写了一个小测试程序,用于测试在CallContext中存储来自线程和任务、线程池线程以及并行线程的数据的场景。在Tasks测试和ThreadPool测试中,当重用同一线程(由ManagedThreadId确定)时,不会再次看到存储在CallContext中的数据。但是,对于Parallel.For,当重用同一线程(由ManagedThreadId确定)时,会再次看到存储在CallContext中的数据。我觉得这很有趣。我不确定这些结果是否符合预期,或者我的程序是否有问题

要尝试每种情况,只需取消注释所需的测试函数

您将看到,任务和线程池线程在并行时的后续线程重用中从未遇到CallContext数据

Parallel.For的行为似乎不一致。当我运行Parallel.For case时,我可以看到一个给定的线程在重用该线程时并不一定总能找到CallContext数据。例如,以下是一次程序运行的输出(UseParallelforUn注释):

线程[9]-无CallContext值
线程[10]-无CallContext值
线程[11]-无CallContext值
线程[12]-无CallContext值
线程[9],cc.thread[9]-值已在CallContext中
{
int id=Thread.CurrentThread。
thread [9] - no CallContext value
thread [10] - no CallContext value 
thread [11] - no CallContext value
thread [12] - no CallContext value
thread [9], cc.thread [9] - value already in CallContext <-- this is expected as this is the main thread
thread [10] - no CallContext value 
thread [13] - no CallContext value
thread [11] - no CallContext value
thread [12] - no CallContext value
thread [14] - no CallContext value
thread [9], cc.thread [9] - value already in CallContext
thread [10], cc.thread [10] - value already in CallContext 
thread [11], cc.thread [11] - value already in CallContext
thread [13] - no CallContext value
thread [15] - no CallContext value
thread [12], cc.thread [12] - value already in CallContext
thread [16] - no CallContext value
thread [14] - no CallContext value
thread [9], cc.thread [9] - value already in CallContext
thread [10] - no CallContext value
thread [17] - no CallContext value
thread [13], cc.thread [13] - value already in CallContext
thread [15] - no CallContext value
thread [11] - no CallContext value
thread [12] - no CallContext value
thread [14], cc.thread [14] - value already in CallContext
thread [18] - no CallContext value
thread [16] - no CallContext value
thread [9], cc.thread [9] - value already in CallContext
thread [10], cc.thread [10] - value already in CallContext 
thread [13] - no CallContext value
thread [15], cc.thread [15] - value already in CallContext
thread [11], cc.thread [11] - value already in CallContext
thread [17] - no CallContext value
thread [19] - no CallContext value
thread [18] - no CallContext value
thread [16], cc.thread [16] - value already in CallContext
thread [14] - no CallContext value
thread [20] - no CallContext value
thread [12], cc.thread [12] - value already in CallContext
thread [9], cc.thread [9] - value already in CallContext
thread [10], cc.thread [10] - value already in CallContext
thread [21] - no CallContext value
thread [15] - no CallContext value
thread [11], cc.thread [11] - value already in CallContext
thread [17], cc.thread [17] - value already in CallContext
thread [13], cc.thread [13] - value already in CallContext
thread [19] - no CallContext value
thread [22] - no CallContext value
thread [18], cc.thread [18] - value already in CallContext
thread [16] - no CallContext value
thread [20] - no CallContext value
thread [14], cc.thread [14] - value already in CallContext
thread [12], cc.thread [12] - value already in CallContext
thread [9], cc.thread [9] - value already in CallContext
thread [10], cc.thread [10] - value already in CallContext
thread [23] - no CallContext value
thread [15], cc.thread [15] - value already in CallContext
thread [21] - no CallContext value
thread [11], cc.thread [11] - value already in CallContext
thread [17] - no CallContext value
thread [13], cc.thread [13] - value already in CallContext
thread [19], cc.thread [19] - value already in CallContext
thread [22] - no CallContext value
thread [16], cc.thread [16] - value already in CallContext
thread [18] - no CallContext value
thread [24] - no CallContext value
thread [20], cc.thread [20] - value already in CallContext
thread [14], cc.thread [14] - value already in CallContext
thread [12], cc.thread [12] - value already in CallContext
thread [9], cc.thread [9] - value already in CallContext
thread [10] - no CallContext value
thread [15], cc.thread [15] - value already in CallContext
thread [21], cc.thread [21] - value already in CallContext
thread [17], cc.thread [17] - value already in CallContext
thread [13], cc.thread [13] - value already in CallContext
thread [22], cc.thread [22] - value already in CallContext
thread [18], cc.thread [18] - value already in CallContext
thread [16], cc.thread [16] - value already in CallContext
thread [14], cc.thread [14] - value already in CallContext
thread [9], cc.thread [9] - value already in CallContext
thread [10], cc.thread [10] - value already in CallContext
thread [15], cc.thread [15] - value already in CallContext
thread [17], cc.thread [17] - value already in CallContext
thread [18], cc.thread [18] - value already in CallContext
thread [16], cc.thread [16] - value already in CallContext
thread [9], cc.thread [9] - value already in CallContext
thread [10], cc.thread [10] - value already in CallContext
thread [17], cc.thread [17] - value already in CallContext
thread [18], cc.thread [18] - value already in CallContext
thread [9], cc.thread [9] - value already in CallContext
thread [10], cc.thread [10] - value already in CallContext
thread [9], cc.thread [9] - value already in CallContext
thread [10], cc.thread [10] - value already in CallContext
thread [9], cc.thread [9] - value already in CallContext
thread [10], cc.thread [10] - value already in CallContext
thread [9], cc.thread [9] - value already in CallContext
thread [10], cc.thread [10] - value already in CallContext
thread [9], cc.thread [9] - value already in CallContext
thread [10], cc.thread [10] - value already in CallContext
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Threading;
using System.Threading.Tasks;
using System.Runtime.Remoting.Messaging;

namespace CallContextTest
{
  class Program
  {
    static void Main(string[] args)
    {
      //UseTasks();
      //UseThreadPool();
      UseParallelFor();

      Console.ReadKey();
    }

    public static void UseThreadPool()
    {
      int totalThreads = 100;

      CountdownEvent finish = new CountdownEvent(totalThreads);

      for (int i = 0; i < totalThreads; i++)
      {
        int ii = i;

        ThreadPool.QueueUserWorkItem(x =>
        {
          int id = Thread.CurrentThread.ManagedThreadId;

          Thread.Sleep(1000);

          object o = CallContext.GetData("threadid");
          if (o == null)
          {
            //Always gets here.
            Console.WriteLine("thread [{0}] - no CallContext value", id);
            CallContext.SetData("threadid", id);
          }
          else
          {
            //Never gets here.
            Console.WriteLine("thread [{0}], cc.thread [{1}] - value already in CallContext", o, id);
          }

          Thread.Sleep(1000);
          finish.Signal();
        });

      }

      finish.Wait();
    }

    public static void UseTasks()
    {
      int totalThreads = 100;
      TaskCreationOptions taskCreationOpt = TaskCreationOptions.None;
      Task task = null;


      Task[] allTasks = new Task[totalThreads];
      for (int i = 0; i < totalThreads; i++)
      {
        int ii = i;
        task = Task.Factory.StartNew(() =>
        {
          int id = Thread.CurrentThread.ManagedThreadId;

          Thread.Sleep(1000);

          object o = CallContext.GetData("threadid");
          if (o == null)
          {
            //Always gets here.
            Console.WriteLine("thread [{0}] - no CallContext value", id);
            CallContext.SetData("threadid", id);
          }
          else
          {
            //Never gets here.
            Console.WriteLine("thread [{0}], cc.thread [{1}] - value already in CallContext", o, id);
          }

          Thread.Sleep(1000);

        }, taskCreationOpt);
        allTasks[i] = task;
      }
      Task.WaitAll(allTasks);
    }

    public static void UseParallelFor()
    {
      int totalThreads = 100;
      Parallel.For(0, totalThreads, i =>
      {
        int ii = i;
        int id = Thread.CurrentThread.ManagedThreadId;

        Thread.Sleep(1000);

        object o = CallContext.GetData("threadid");
        if (o == null)
        {
          //Sometimes gets here.
          Console.WriteLine("thread [{0}] - no CallContext value", id);
          CallContext.SetData("threadid", id);
        }
        else
        {
          //Sometimes gets here as threads are reused.
          Console.WriteLine("thread [{0}], cc.thread [{1}] - value already in CallContext", o, id);
        }

        Thread.Sleep(1000);

      });
    }

  }
}