线程上下文切换 多线程下的调用上下文 : CallContext( 二 )


public void TestLogicalGetSetData(){// 主线程执行Console.WriteLine($"Current ThreadId={Thread.CurrentThread.ManagedThreadId}");var user = new User(){Id = DateTime.Now.ToString(),Name = "Edison"};CallContext.LogicalSetData("key", user);var value1 = CallContext.LogicalGetData("key");Console.WriteLine(user == value1);// 异步线程执行Task.Run(() =>{Console.WriteLine($"Current ThreadId={Thread.CurrentThread.ManagedThreadId}");var value2 = CallContext.LogicalGetData("key");Console.WriteLine(value2 == null ?"NULL" : (value2 == value1).ToString());Thread.Sleep(1000);value2 = CallContext.LogicalGetData("key");Console.WriteLine(value2 == null ?"NULL" : (value2 == value1).ToString());});// 主线程执行Console.WriteLine($"Current ThreadId={Thread.CurrentThread.ManagedThreadId}");// 清理数据槽CallContext.FreeNamedDataSlot("key");var value3 = CallContext.LogicalGetData("key");Console.WriteLine(value3 == null ?"NULL" : (value3 == value1).ToString());}这段示例代码的运行结果如下图所示:

线程上下文切换 多线程下的调用上下文 : CallContext

文章插图
根据上图所示的结果,基本可以得出以下三个结论:
1、FreeNamedDataSlot只能清除当前线程的数据槽,不能清除子线程的数据槽;
2、LogicalSetData、LogicalGetData可用于在多线程环境下传递数据;
3、FreeNamedDataSlot清除当前线程的数据槽后,之前已经运行的子任务,不受影响;
测试3:LogicalGetData后修改传递的数据
在多线程环境下传递共享对象数据,如果某个线程通过LogicalGetData后对其进行了修改又重新LogicalSetData会怎样?
public void TestLogicalGetSetDataV2(){// 主线程执行Console.WriteLine($"Current ThreadId={Thread.CurrentThread.ManagedThreadId}");var user = new User(){Id = DateTime.Now.ToString(),Name = "Edison"};CallContext.LogicalSetData("key", user);var value1 = CallContext.LogicalGetData("key");Console.WriteLine(user == value1);// 异步线程同步执行:加了.Wait()Task.Run(() =>{Console.WriteLine($"Current ThreadId={Thread.CurrentThread.ManagedThreadId}");var value2 = CallContext.LogicalGetData("key");Console.WriteLine(value2 == null ?"NULL" : (value2 == value1).ToString());CallContext.FreeNamedDataSlot("key");value2 = CallContext.LogicalGetData("key");Console.WriteLine(value2 == null ?"NULL" : (value2 == value1).ToString());}).Wait();// 异步线程同步执行:加了.Wait()Task.Run(() =>{Console.WriteLine($"Current ThreadId={Thread.CurrentThread.ManagedThreadId}");var value2 = CallContext.LogicalGetData("key") as User;Console.WriteLine(value2 == null ?"NULL" : (value2 == value1).ToString());        value2.Name = "Leo";CallContext.LogicalSetData("key", new User() { Id = DateTime.Now.ToString(), Name = "Jack" }); // 只影响当前线程value2 = CallContext.LogicalGetData("key") as User;Console.WriteLine(value2 == null ?"NULL" : (value2 == value1).ToString());Console.WriteLine($"User.Name={value2.Name}");}).Wait();// 主线程执行Console.WriteLine($"Current ThreadId={Thread.CurrentThread.ManagedThreadId}");var value3 = CallContext.LogicalGetData("key") as User;Console.WriteLine(value3 == null ?"NULL" : (value3 == value1).ToString());Console.WriteLine($"User.Name={value3.Name}");}上面示例代码的运行结果如下图所示:
线程上下文切换 多线程下的调用上下文 : CallContext

文章插图
根据上面的示例运行结果,我们又可以得到以下一些结论:
1、FreeNamedDataSlot只能清除当前线程的数据槽
2、LogicalSetData只会存储当前线程以及子线程的数据槽;
3、LogicalGetData获取的是当前线程或父线程的数据槽对象,拿到的是对象的引用,因此如果对其进行修改,会影响父线程读取的一致性,在关系型数据库中也被称为不可重复读 。


以上关于本文的内容,仅作参考!温馨提示:如遇健康、疾病相关的问题,请您及时就医或请专业人士给予相关指导!

「四川龙网」www.sichuanlong.com小编还为您精选了以下内容,希望对您有所帮助: