那么这个函数也是线程安全的。
这里有一个容易被忽略的问题,运算符。并不是所有的运算符(尤其是重载后的运算符)都是线程安全的。
四、互斥锁
有时候我们不得不面对线程不安全的问题,比如说在一开始提出来的那个例子,多线程完成100次任务,我们怎样才能解决这个问题,一个简单的办法就是给共享资源加上互斥锁。在C#中这很简单。比如一开始的那个例子:
public static class Environment
{public static int count = 0;//全局计数器
}
//…
void ThreadMethod()//运行在每个线程的方法
{
while( true )
{
lock ( typeof( Environment ) )
{
if ( count >= 100 )//如果达到任务指标
break;//中断线程执行
DoSomething();//完成某个任务
count++;}}}
通过互斥锁,使得一个线程在使用count字段的时候,其他所有的线程都无法使用,而被阻塞等待。达到了避免线程冲突的效果。
当然,这样的锁会使得这个多线程程序退化成同时只有一个线程在跑,所以我们可以把count++提前,使得lock的范围缩小,如这样:
void ThreadMethod()//运行在每个线程的方法
{
while( true )
{
lock ( typeof( Environment ) )
{
if ( count++ >= 100 )//如果达到任务指标
break;//中断线程执行
}
DoSomething();//完成某个任务
}}
最后来聊聊SyncRoot的问题。
用.NET的一定会有很多朋友困惑,为什么对一个容器加锁,需要这样写:
lock( Container.SyncRoot )
而不是直接lock( Container )
因为锁定一个容器并不能保证不会对这个容器进行修改,考虑这样一个容器:
public class Collection
{
private ArrayList _list;
public Add( object item )
{
_list.Add( item );
}
public object this[ int index ]
{
get { return _list[index]; }
set { _list[index] = value;}
}}
看起来,将其lock起来后,就万事大吉了,没有人能修改这个容器,但实际上这个容器不过是用一个ArrayList实例来实现的,如果某段代码绕过这个容器而直接操作_list的话,则对这个容器对象lock也不可能保证容器不被修改了。