• .NET 如何阻止线程执行上下文的传递


    (1)何为线程的执行上下文

    在.NET中,每一个线程都会包含一个执行上下文,执行上下文是指线程运行中某时刻的上下文概念,类似于一个动态过程的快照(SnapShot)。在.NET中,System.Threading中的ExecutionContext类型代表了一个执行上下文,该执行上下文会包含:安全上下文、调用上下文、本地化上下文、事务上下文和CLR宿主上下文等等。通常情况下,我们将所有这些综合成为线程的上下文。

    (2)执行上下文的流动

    当程序中新建一个线程时,执行上下文会自动地从当前线程流入到新建的线程之中,这样做可以保证新建的线程天生就就有和主线程相同的安全设置和文化等设置。下面的示例代码通过修改安全上下文来展示线程上下文的流动性,主要使用到ExecutionContext类的Capture方法来捕获当前想成的执行上下文。

    ① 首先定义一些辅助方法,封装了文件的创建、删除和文件访问权限检查:
    partial class Program
    {
    private static void CreateTestFile()
    {
    if (!File.Exists(testFile))
    {
    FileStream stream = File.Create(testFile);
    stream.Dispose();
    }
    }

        private static void DeleteTestFile()
        {
            if (File.Exists(testFile))
            {
                File.Delete(testFile);
            }
        }
    
        // 尝试访问测试文件来测试安全上下文
        private static void JudgePermission(object state)
        {
            try
            {
                // 尝试访问文件
                File.GetCreationTime(testFile);
                // 如果没有异常则测试通过
                Console.WriteLine("权限测试通过");
            }
            catch (SecurityException)
            {
                // 如果出现异常则测试通过
                Console.WriteLine("权限测试没有通过");
            }
            finally
            {
                Console.WriteLine("------------------------");
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    ② 其次在入口方法中使主线程和创建的子线程访问指定文件来查看权限上下文流动到子线程中的情况:(这里需要注意的是由于在.NET 4.0及以上版本中FileIOPermission的Deny方法已过时,为了方便测试,将程序的.NET版本调整为了3.5)

    partial class Program
    {
    private const string testFile = @“C:\TestContext.txt”;

        static void Main(string[] args)
        {
            try
            {
                CreateTestFile();
                // 测试当前线程的安全上下文
                Console.WriteLine("主线程权限测试:");
                JudgePermission(null);
                // 创建一个子线程 subThread1
                Console.WriteLine("子线程权限测试:");
                Thread subThread1 = new Thread(JudgePermission);
                subThread1.Start();
                subThread1.Join();
                // 现在修改安全上下文,阻止文件访问
                FileIOPermission fip = new FileIOPermission(FileIOPermissionAccess.AllAccess, testFile);
                fip.Deny();
                Console.WriteLine("已成功阻止文件访问");
                // 测试当前线程的安全上下文
                Console.WriteLine("主线程权限测试:");
                JudgePermission(null);
                // 创建一个子线程 subThread2
                Console.WriteLine("子线程权限测试:");
                Thread subThread2 = new Thread(JudgePermission);
                subThread2.Start();
                subThread2.Join();
                // 现在修改安全上下文,允许文件访问
                SecurityPermission.RevertDeny();
                Console.WriteLine("已成功恢复文件访问");
                // 测试当前线程安全上下文
                Console.WriteLine("主线程权限测试:");
                JudgePermission(null);
                // 创建一个子线程 subThread3
                Console.WriteLine("子线程权限测试:");
                Thread subThread3 = new Thread(JudgePermission);
                subThread3.Start();
                subThread3.Join();
    
                Console.ReadKey();
            }
            finally
            {
                DeleteTestFile();
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    在这里插入图片描述
    (3)阻止上下文的流动

    有的时候,系统需要子线程拥有新的上下文。抛开功能上的需求,执行上下文的流动确实使得程序的执行效率下降很多,线程上下文的包装是一个成本较高的工作,而有的时候这样的包装并不是必须的。在这种情况下,我们如果需要手动地防止线程上下文的流动,常用的有下列两种方法:

    ① System.Threading.ThreadPool类中的UnsafeQueueUserWorkItem方法

    ② ExecutionContext类中的SuppressFlow方法

    下面的代码示例展示了如何使用上面两种方法阻止执行上下文的流动:
    partial class Program
    {
    private const string testFile = @“C:\TestContext.txt”;

        static void Main(string[] args)
        {
            try
            {
                CreateTestFile();
                // 现在修改安全上下文,阻止文件访问
                FileIOPermission fip = new FileIOPermission(FileIOPermissionAccess.AllAccess, testFile);
                fip.Deny();
                Console.WriteLine("已成功阻止文件访问");
                // 主线程权限测试
                Console.WriteLine("主线程权限测试:");
                JudgePermission(null);
                // 使用UnsafeQueueUserWorkItem方法创建一个子线程
                Console.WriteLine("子线程权限测试:");
                ThreadPool.UnsafeQueueUserWorkItem(JudgePermission, null);
    
                Thread.Sleep(1000);
    
                // 使用SuppressFlow方法
                using (var afc = ExecutionContext.SuppressFlow())
                {
                    // 测试当前线程安全上下文
                    Console.WriteLine("主线程权限测试:");
                    JudgePermission(null);
                    // 创建一个子线程 subThread1
                    Console.WriteLine("子线程权限测试:");
                    Thread subThread1 = new Thread(JudgePermission);
                    subThread1.Start();
                    subThread1.Join();
                }
    
                // 现在修改安全上下文,允许文件访问
                SecurityPermission.RevertDeny();
                Console.WriteLine("已成功恢复文件访问");
                // 测试当前线程安全上下文
                Console.WriteLine("主线程权限测试:");
                JudgePermission(null);
                // 创建一个子线程 subThread2
                Console.WriteLine("子线程权限测试:");
                Thread subThread2 = new Thread(JudgePermission);
                subThread2.Start();
                subThread2.Join();
    
                Console.ReadKey();
            }
            finally
            {
                DeleteTestFile();
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51

    在这里插入图片描述
    在这里插入图片描述

  • 相关阅读:
    ubuntu18.04服务搭建yolov5开发环境
    国产瑞芯微RK3399 硬件设计之 HDMI2.0 的注意事项
    Win10一键重装系统后计算机图标怎么调出来
    4.1.5-检查网页内容是否存在信息泄露
    【数据结构与算法】LinkedList与链表
    Kafka - 05 Kafka生产者| 消息发送方式 | 序列化器 | 分区器 | 拦截器 |生产者配置参数
    八大排序算法
    Curvilinear coordinates
    EZwall国标协议添加第三方网络视频录像机配置步骤
    Hadoop运维之:配置文件作用概述ing
  • 原文地址:https://blog.csdn.net/u013400314/article/details/126874432