购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP


陷阱26
三思而行
——使用值类型进行线程同步

1.陷阱产生的场景

无论在什么环境和机制下编写多线程程序都需要考虑线程同步的问题,因为很难找到同属于一个应用程序却又完全不相干的多线程。本实例将讨论使用值类型进行线程同步的问题。

例4.26 使用值类型进行线程同步(光盘位置:光盘\MR\Instance\4\26\ SynchronBy Value),该实例的实现过程如下。

本实例创建一个控制台应用程序,先在应用程序下创建一个类文件SynchronValue.cs,该文件包含一个名称为SynchronValue的类,其代码如下所示:

说明

定义SynchronValue类时,需要引用System.Threading命名空间。

在控制台应用程序的入口方法Main中编写如下代码:

编译后运行本实例,在运行时却出现如图4.55所示的异常提示,异常信息提示“从不同步的代码块中调用了对象同步方法”。

图4.55 异常提示

2.陷阱的分析

.NET的线程同步机制是基于同步块实现的,在.NET的框架中,每个堆内的对象都会拥有一个同步索引字段用来指向同步块的位置。值类型对象是分配在堆栈上的,也就是说,值类型对象没有同步索引字段,所以直接使用值类型对象无法实现线程同步。

具体应用到程序中时,对值类型的变量应用lock关键字或者Monitor类的Enter方法和Exit方法会产生不一样的结果。对于lock关键字来说,使用值类型会直接导致一个编译错误,错误信息如图4.56所示。

图4.56 错误信息

但是如果使用Monitor类,编译器则无法为程序员检测出这一类的错误,与使用引用类型的情况一样,每次调用Monitor.Enter方法时,都会对值类型进行装箱,每一次装箱都会导致一个新的堆内对象的产生,所有的线程都在访问不同对象的同步块,导致线程同步完全失败。更为严重的是,当某个线程试图对值类型对象调用Monitor.Exit方法时,装箱同样会发生,这时就意味着程序尝试对一个没有分配同步块的对象进行同步退出,所以才会导致如图4.55所示的运行时异常。

3.陷阱的解决方法

根据上面的分析可知,不可以使用值类型进行线程同步,所以解决方法是将Synchron Value类中的syn字段改成引用类型,修改后的代码如下: ZroTT9a1iJHhN6pJ6bhhnv7zhUDVcWKU3o2VZkWDvpHBvZne6iYR94T0hO6HoCVB

点击中间区域
呼出菜单
上一章
目录
下一章
×