C#线程同步的几种方法总结线程同步的几种方法总结
我们在编程的时候,有时会使用多线程来解决问题,比如你的程序需要在后台处理一大堆数据,但还要使用户界面处于可操作
状态;或者你的程序需要访问一些外部资源如数据库或网络文件等。这些情况你都可以创建一个子线程去处理,然而,多线程
不可避免地会带来一个问题,就是线程同步的问题。如果这个问题处理不好,我们就会得到一些非预期的结果。
在网上也看过一些关于线程同步的文章,其实线程同步有好几种方法,下面我就简单的做一下归纳。
一、一、volatile关键字关键字
volatile是最简单的一种同步方法,当然简单是要付出代价的。它只能在变量一级做同步,volatile的含义就是告诉处理器, 不
要将我放入工作内存, 请直接在主存操作我。(【转自www.bitsCN.com 】)因此,当多线程同时访问该变量时,都将直接
操作主存,从本质上做到了变量共享。
能够被标识为volatile的必须是以下几种类型:(摘自MSDN)
• Any reference type.
• Any pointer type (in an unsafe context).
• The types sbyte, byte, short, ushort, int, uint, char, float, bool.
• An enum type with an enum base type of byte, sbyte, short, ushort, int, or uint.
如:
public class A
{
private volatile int _i;
public int I
{
get { return _i; }
set { _i = value; }
}
}
但volatile并不能实现真正的同步,因为它的操作级别只停留在变量级别,而不是原子级别。如果是在单处理器系统中,是没
有任何问题的,变量在主存中没有机会被其他人修改,因为只有一个处理器,这就叫作processor Self-Consistency。但在多
处理器系统中,可能就会有问题。 每个处理器都有自己的data cach,而且被更新的数据也不一定会立即写回到主存。所以可
能会造成不同步,但这种情况很难发生,因为cach的读写速度相当快,flush的频率也相当高,只有在压力测试的时候才有可
能发生,而且几率非常非常小。
二、二、lock关键字关键字
lock是一种比较好用的简单的线程同步方式,它是通过为给定对象获取互斥锁来实现同步的。它可以保证当一个线程在关键代
码段的时候,另一个线程不会进来,它只能等待,等到那个线程对象被释放,也就是说线程出了临界区。用法:
public void Function()
{
object lockThis = new object ();
lock (lockThis)
{
// Access thread-sensitive resources.
}
}
ock的参数必须是基于引用类型的对象,不要是基本类型像bool,int什么的,这样根本不能同步,原因是lock的参数要求是对
象,如果传入int,势必要发生装箱操作,这样每次lock的都将是一个新的不同的对象。最好避免使用public类型或不受程序控
制的对象实例,因为这样很可能导致死锁。特别是不要使用字符串作为lock的参数,因为字符串被CLR“暂留”,就是说整个应
用程序中给定的字符串都只有一个实例,因此更容易造成死锁现象。建议使用不被“暂留”的私有或受保护成员作为参数。其实
某些类已经提供了专门用于被锁的成员,比如Array类型提供SyncRoot,许多其它集合类型也都提供了SyncRoot。
所以,使用lock应该注意以下几点:
1、如果一个类的实例是public的,最好不要lock(this)。因为使用你的类的人也许不知道你用了lock,如果他new了一个实
例,并且对这个实例上锁,就很容易造成死锁。
2、如果MyType是public的,不要lock(typeof(MyType))
3、永远也不要lock一个字符串
三、三、System.Threading.Interlocked
对于整数数据类型的简单操作,可以用 Interlocked 类的成员来实现线程同步,存在于System.Threading命名空间。
评论0