\t\t多线程有关安全性

有关安全性

         如果你再看看ThreadPool类,你会看到有两个方法我们没有用到,UnsafeQueueUserWorkItem UnsafeRegisterWaitForSingleObject 为了完全理解这些方法,首先,我们必须回忆 .NET框架中安全策略是怎么运作的。

         Windows安全机制是关注资源。操作系统本身允许对文件,用户,注册表键值和任何其它的系统资源设定权限。这种方法对应用系统的用户认证非常有效,但当出现用户对他使用的系统产生不信任的情况时,这就会有些局限性。例如这些程序是从Internet下载的。在这种情况下,一旦用户安装了这个程序,它就可以执行用户权限范围内的任何操作。举个例子,假如用户可以删除他公司内的任何共享文件,任何从Internet下载的程序也都可以这样做。

         .NET 提供了应用到程序的安全性策略,而不是用户。这就是说,在用户权限的范围内,我们可以限制任何执行单元(程序集)使用的资源。通过MMC,我们可以根据条件定义一组程序集,然后为每组设置不同的策略,一个典型的例子就是限制从Internet下载的程序访问磁盘的权限。

         为了让这个功能运转起来,.NET 框架必须维护一个不同程序集之间的调用栈。假设一个应用没有权限访问磁盘,但是它调用了一个对整个系统都可以访问的类库,当第二个程序集执行一个磁盘的操作时,设置到这个程序集的权限允许这样做,但是权限不会被应用到主叫程序集,.NET不仅要检查当前程序集的权限,而且会检查整个调用栈的权限。这个栈已经被高度优化了,但是它们给两个不同程序集之间的调用增加了额外的负担。

         UnsafeQueueUserWorkItem , UnsafeRegisterWaitForSingleObject QueueUserWorkItem , RegisterWaitForSingleObject两个方法类似。由于是非安全版本不会维护它们执行函数之间的调用栈,所以非安全版本运行的更快些。但是回调函数将只在当前程序集的安全策略下执行,它就不能应用权限到整个调用栈中的程序集。

         我的建议是仅在性能非常重要的、安全已经控制好的极端情况下才用非安全版本。例如,你构建的应用程序不会被其它的程序集调用,或者仅被很明确清楚的程序集使用,那么你可以用非安全版本。如果你开发的类库会被第三方应用程序中使用,那么你就不应该用这些方法,因为它们可能用你的库获取访问系统资源的权限。

         在下面例子中,你可以看到用UnsafeQueueUserWorkItem方法的风险。我们将构建两个单独的程序集,在第一个程序集中我们将在线程池中创建一个文件,然后我们将导出一个类以使这个操作可以被其它的程序集执行。

using System;
using System.Threading;
using System.IO;
namespace ThreadSecurityTest
{
    public class PoolCheck
    {
       public void CheckIt()
       {
          ThreadPool.QueueUserWorkItem(new WaitCallback(UserItem), null);
       }
       private void UserItem(object obj)
       {
          FileStream fs = new FileStream("test.dat", FileMode.Create);
          fs.Close();
          Console.WriteLine("File created");
       }
    }
}

第二个程序集引用了第一个,并且用了CheckIt 方法去创建一个文件:

using System;
namespace ThreadSecurityTest
{
    class MainApp
    {
       static void Main()
       {
          PoolCheck pc = new PoolCheck();
          pc.CheckIt();
          Console.ReadLine();
       }
    }
}

编译这两个程序集,然后运行main应用。默认情况下,你的应用被配置为允许执行磁盘操作,所以系统成功生成文件。

      File created

现在,打开.NET框架的配置。为了简化这个例子,我们仅创建一个代码组关联到main应用。接着展开 运行库安全策略/ 计算机/ 代码组/ All_Code /,增加一个叫ThreadSecurityTest的组。在向导中,选择Hash 条件并导入Hash到我们的应用中,设置为Internet 级别,并选择“该策略级别将只具有与此代码组关联的权限集中的权限”选项。

运行应用程序,看看会发生什么情况:

Unhandled Exception: System.Security.SecurityException: Request for the 
   permission of type System.Security.Permissions.FileIOPermission, 
      mscorlib, Version=1.0.3300.0, Culture=neutral, 
         PublicKeyToken=b77a5c561934e089 failed.

我们的策略开始工作,系统已经不能创建文件了。这是因为.NET框架为我们维护了一个调用栈才使它成为了可能,虽然创建文件的库有权限去访问系统。

现在把库中的QueueUserWorkItem替换为UnsafeQueueUserWorkItem再次编译程序集,然后运行Main程序。现在的结果是:

File created

即使我们的系统没有足够的权限去访问磁盘,但我们已经创建了一个向整个系统公开它的功能的库,却没有维护它的调用栈。记住一个金牌规则: 仅在你的代码不允许让其它的应用系统调用,或者当你想要严格限制访问很明确清楚的程序集,才使用非安全的函数。

我们知道了为什么在我们的服务器应用中需要使用线程池来优化资源和CPU的利用。我们学习了一个线程池是如何实现的,需要考虑多个因素如:CPU使用的百分比,队列请求或者系统的处理器数量。

         .NET提供了丰富的线程池的功能以让我们的应用程序使用, 并且与.NET框架的类紧密地集成在一起。这个线程池是高度优化了的,它只需要最少的CPU时间和资源,而且总能适应目标平台。

         因为与框架集成在一起,所以框架中的大部分类都提供了使用线程池的内在功能,给开发人员提供了集中管理和监视应用中的线程池的功能。鼓励第三方组件使用线程池,这样它们的客户就可以享受.NET所提供的全部功能。允许执行用户函数,定时器,I/O操作和同步对象。

         假如你在开发服务器应用系统,只要有可能就在你的请求处理系统中使用线程池。或者你开发了一个让服务器程序使用的库,那么尽可能提供系统线程池的异步对象处理。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值