多线程之旅(10)_QueueUserWorkItem和UnsafeQueueUserWorkItem的区别
这是个比较冷门的点,是我在写多线程之旅(2)_创建一个属于自己的精简线程池_线程调度策略——附C#源码这篇文章时,发现在做线程队列时,官方选用的是UnsafeQueueUserWorkItem,而不是常见的QueueUserWorkItem,所以后续我就对这两个方法调查一番,发现资料也不多,总结一下。
一、官方定义
首先看一下官方的定义:
来源:
https://docs.microsoft.com/zh-cn/dotnet/api/system.threading.threadpool.queueuserworkitem?view=netframework-4.8
https://docs.microsoft.com/zh-cn/dotnet/api/system.threading.threadpool.unsafequeueuserworkitem?view=netframework-4.8
(1)QueueUserWorkItem(WaitCallback, Object)
将方法排入队列以便执行,并指定包含该方法所用数据的对象。 此方法在有线程池线程变得可用时执行。
参数:
WaitCallback,它表示要执行的方法。
Object,包含方法所用数据的对象。
(2)UnsafeQueueUserWorkItem(WaitCallback, Object)
将指定的委托排队到线程池,但不会将调用堆栈传播到辅助线程。
参数:
WaitCallback,表示当线程池中的线程选择工作项时调用的委托。
Object,在接受线程池服务时传递给委托的对象。
二、解析
看着上面的官方解释,一如既往的迷,不用担心是之上问题,或许是因为翻译问题使得很难理解。
下面我用一篇文章(http://www.csframework.com/archive/2/arc-2-20110727-1759.htm)中的一段描述来解释这个问题:
threadpool类有一个UnsafeQueueUserWorkItem方法。该方法与平时调用的QueueUserWorkItem方法非常相似。下面先简单介 绍一下这两个方法的区别:
当有线程试图访问一个受限资源(如打开一个文件)时,clr将执行一个代码访问安全(code access security, cas)检查。也就是说,clr将检查调用线程的调用堆栈中的所有程序集是否都有访问资源的许可权限。如果有一些程序集没有所需 的许可权限,clr将抛出一个securityexception异常。假设正在执行代码的线程所在的程序集没有打开文件的许可权限,那么在线程试图打开文件时,clr将抛出一个securityexception异常。
为让线程继续运行,线程可以在线程池的队列加入一个工作项,让线程池中的线程来执行打开文件的代码。当然这必须在拥 有合适许可权限的程序集中进行。这种“工作区”智取安全权限的现象可以允许怀恶意的代码对受限资源进行严重破坏。为阻止这 种获得安全权限的方式,QueueUserWorkItem方法内部遍历调用线程的堆栈,并捕获所有被授予的安全权限。然后,当线程池中的线程开始执行时,这些权限再与线程结合。因此,线程池中的线程以调用QueueUserWorkItem方法的线程相同的权限集来完成运行。
(看着是有些绕,简单说呢,QueueUserWorkItem作为一种安全的线程池机制,其内部有一个功能,就是能遍历调用线程池中线程的‘堆栈’,获取堆栈中程序集所具有的安全权限。当堆栈对该线程调用时,这个线程的就继承了调用他的堆栈内容所具有的权限。这样就避免了权限较小的堆栈通过调用权限较大的线程,来获取非法数据。
就好比堆栈里的内容没有打开文件的权限,但是线程池中的线程可以打开文件,那么堆栈通过调用线程池里的线程来打开文件,从而获取打开文件的权限。)
OK,我们再来了解一下UnsafeQueueUserWorkItem
遍历线程的堆栈并捕获所有的安全权限与性能紧密相关。如果希望改进受计算限制的异步操作的排队性能,可以调用 UnsafeQueueUserWorkItem方法。该方法只将工作项加入到线程池的队列中,而不遍历调用线程的堆栈。最后结果是这个方法比 QueueUserWorkItem方法执行得快,但它在应用程序中打开了一个潜在的安全漏洞。仅当可以确认线程池中的线程执行的代码不触及受限资源时,或确信接触这部分资源不会出现问题时,我们才可以调用unsafequeueuserwork-item方法。同样,还需注意调用该方 法需要使securitypermission的controlpolicy标记和controlevidence标记开启,可阻止未信任的代码偶然或故意提升它的许可权 限。
(有了上面的铺垫,UnsafeQueueUserWorkItem就很好理解了,为了追求效率,UnsafeQueueUserWorkItem对堆栈里的内容信任,不再去遍历堆栈信息,读取权限,而是直接执行。)
三、其他
还有一篇文章(https://www.cnblogs.com/JeffreyZhao/archive/2009/07/22/thread-pool-1-the-goal-and-the-clr-thread-pool.html)中的一段话,提到了两者的关联,贴上来
我们在编写程序的时候,可以使用ThreadPool类的两个静态方法:QueueUserWorkItem和UnsafeUserQueueWorkItem向CLR线程池中添加任务(一个WorkCallback委托对象),这两个方法的区别,在于前者会收集调用方的ExecutionContext,也就是保留了的当前线程的执行信息(如认证或语言文化等),使任务最终会在“创建”时刻的环境中执行2——后者就不会。因此,如果比较两个方法的绝对性能,Unsafe方法会略胜一筹。但是平时还是建议使用QueueUserWorkItem方法,因为保留执行上下文会避免很多麻烦事情,且这点性能损耗其实算不上什么。
这段话表述不是很清楚,但大概意思也表明了QueueUserWorkItem方法在处理线程时会做更多的信息评判,更加安全。而相比之下UnsafeQueueUserWorkItem的执行效率更高。
多线程之旅(10)_QueueUserWorkItem和UnsafeQueueUserWorkItem的区别相关推荐
- WCF后续之旅(10): 通过WCF Extension实现以对象池的方式创建Service Instance
我们知道WCF有3种典型的对service instance进行实例化的方式,他们分别与WCF的三种InstanceContextMode相匹配,他们分别是PerCall,PerSession和Sin ...
- C#多线程之旅(七)——终止线程
阅读目录 一.什么时候用Thread.Abort(); 二.Thread.Abort的用法 三.无法终止线程的情形 四.Catch块中抛出异常 五.Finally块中抛出异常 六.Abort调用的时间 ...
- C#多线程之旅(3)——线程池
阅读目录 代码下载 一.介绍 二.通过TPL进入线程池 三.不用TPL进入到线程池 v博客前言 先交代下背景,写<C#多线程之旅>这个系列文章主要是因为以下几个原因:1.多线程在C/S和B ...
- 多线程之旅之四——浅谈内存模型和用户态同步机制
用户态下有两种同步结构的 volatile construct: 在简单数据类型上原子性的读或者写操作 interlocked construct:在简单数据类型上原子性的读和写操作 (在这里还 ...
- C#多线程之旅(4)——APM初探
阅读目录 一.简单的串行执行程序 二.使用委托来实现APM 源码地址:https://github.com/Jackson0714/Threads C#多线程之旅(4)--APM初探 v博客前言 先交 ...
- jmu-Java-07多线程-同步访问 (10分)
jmu-Java-07多线程-同步访问 (10分) 现已有Account类,拥有 属性: private int balance 方法: 相应的getter方法. 要求为该类编写: void depo ...
- Linux 之旅 10:Shell 脚本
Linux 之旅 10:Shell 脚本 (图片来自shell/bash脚本编程) Linux 上的 Shell 脚本可以看做是类似于Windows上的批处理程序(.bat)一样的东西,其本质就是将一 ...
- 小猪的Python学习之旅 —— 10.三分钟上手Requests库
小猪的Python学习之旅 -- 10.三分钟上手Requests库 标签:Python 一句话概括本文: 本节讲解Requests库的常见使用,以及一个实战项目: 扒取某一篇微信文章里所有的图片,视 ...
- (10)FPGA与ASIC区别
(10)FPGA与ASIC区别 1 文章目录 1)文章目录 2)FPGA入门与提升课程介绍 3)FPGA简介 4)FPGA与ASIC区别 5)技术交流 6)参考资料 2 FPGA入门与提升课程介绍 1 ...
最新文章
- 西农计算机考研专业课压分,考研:西农大计算机初试第一名被淘汰,倒数第一成功逆袭...
- 毕向东Java基础教程(适合初学者入门的Java基础视频)
- Citrix Netscaler负载均衡算法
- android 5.0 ios 8,Android 5.0和iOS8.1哪个好?安卓5.0与iOS8.1区别对比
- 160 - 34 Cruehead.3
- python的知识点运用_程序猿在Python编程中不得不使用的十二种基础知识
- 在 Visual Studio .NET 中使用 SQL Server 2000 创建数据库应用程序(1)
- python requests 乱码_python3 requests 抓取乱码问题
- 《Unix网络编程》卷一(简介TCP/IP、基础套接字编程)
- 重启apache下php,linux下apache重启并查看php环境
- 蓝桥杯 ADV-72 算法提高 一元一次方程
- ASP.NET中的回调技术(CallBack)
- ftp linux 开启验证_Linux认证系统管理:linux下搭建ftp
- 【原】Python基础-__init__
- ARTS打卡计划第一周-Tips-ControllerAdvice的使用
- 代码规范化的七大原则
- 代码抛出异常后进行事务回滚的两种方式(Spring @Transactional注解)
- 51单片机最小系统的c语言,89c51单片机最小系统,89c51最小系统原理图的功能详解...
- 程序员夏天穿格子衫,那么冬天穿什么?答案扎心了
- 监听通知栏内容,获取通知栏消息,安卓原生SDK扩展
热门文章
- 比尔盖茨致青年的黄金准则(双语)
- ACL21 - Named Entity Recognition with Small Strongly Labeled and Large Weakly Labeled Data
- joinquant RSI策略邮件提醒 python发送邮件
- joinquant量化是什么?
- 还在问怎么找货源?除了1688这个平台值得推荐!
- three 环绕旋转,卫星可以各个角度绕星球旋转
- 手机端访问PC端网站判断识别跳转至手机端页面代码集锦
- 好久没登录hotmail了今天一登这麻烦啊
- 集成基于CAS协议的单点登陆
- 【论文阅读】Impact of Texture Information on Crop Classificationwith Machine Learning and UAV Images