.net的同步

方法同步:(使用MethodImplAttribute类)
该类属于命名空间 System.Runtime.CompilerServices.作用是同时只允许一个线程调用该方法。
使用方法如下:
[MethodImpl(MethodImplOptions.Synchronized)]
public void doSomeWork(){......}

代码区同步:
1 Monitor类
使用 Monitor 锁定对象类型而不是值类型。
它是未绑定的,也就是说可以直接从任何上下文调用它。
不能创建 Monitor 类的实例。
使用 Enter 和 Exit 方法标记临界区的开头和结尾。
建议:先Enter,然后将这些指令放在 try 块中,将 Exit 指令放在 finally 块中。
使用方法:
Monitor.Enter(this);
tatch{//Code}
catch{//code}
finally{Monitor.Exit(this);}

关于Wait()和Pulse():当执行Wait方法,正在访问该对象的线程就会进入等待状态,直到等到一个唤醒的信号。 Pulse&PulseAll方法用于给等待线程发送信号。
当锁定非自身对象的时候,可以使用wait使得使用该对 象的线程暂时睡眠,pulse使得唤醒其他使用该对象的线程并让自身睡眠

关于TryEnter():该方法与 Enter类似,区别在于当无法获得锁定时,会在指定间隔时间之后重新尝试获得锁定。

2 lock
最常用的方法:
lock(this)
{//code
}

3 关于线程安全包装器
假设有myclass类,该类包含void方法DoSome,可以写如下线程安全包装器:
public class Wrapper
{
   private myclass _m;
   public Wrapper(){_m=new myclass();}
   public void DoSome()
   {
       lock(_m){this._m.DoSome();}
   }
}
说明:
这里获得锁的不是Wrapper对象,我们需要线程安全的是 myclass而不是包装器
线程安全包装器一般在处理第三方类的时候使用

4 ReadWriteLock类
在任一特定时刻,它允许多个线程同时进行读访问,或者允许单个线程进行写访问。就是说,当读锁存在时, 不可获得写锁,可获得读锁。当所有锁释放时可以获得写锁。当写锁存在时无法获得任何锁。
在资源不经常发生更改的情况下, ReaderWriterLock 所提供的吞吐量比简单的一次只允许一个线程的锁(如 Monitor)更高。在多数访问为读访问,而写访问频率较低、持续时间也比较短的情况下,ReaderWriterLock 的性能最好。多个读线程与单个写线程交替进行操作,所以读线程和写线程都不会长时间阻塞。
一个线程可以持有读线程锁或写线程锁,但不能同时持有两者。若要获取写线程锁,请使用UpgradeToWriterLock和 DowngradeFromWriterLock,而不要通过释放读线程锁的方式获取。
使用方法:
public class Account
{
 int val ;
 ReaderWriterLock rwl = new ReaderWriterLock();
 
 public int Read()
 {
  rwl.AcquireReaderLock(Timeout.Infinite);
  int iRet = 0;
  try
  {
   iRet = val;
  }
  finally
  {
   rwl.ReleaseReaderLock();
  }
  return iRet;
 }
 
 public void Write(int x)
 {
  rwl.AcquireWriterLock(Timeout.Infinite);
  try
  {
   val = x;
  }
  finally
  {
   rwl.ReleaseWriterLock();
  }
 }
}
注意:
I  锁的获取设定了超时时间(下文会说明)
II 锁的释放在finally代码块中

关于获取锁的超时时间:
多数在 ReaderWriterLock 上获取锁的方法都采用超时值。使用超时可以避免应用程序中出现死锁。例如,某个线程可能获取了资源1上的写线程锁,然后请求资源2上的读线程锁;同时,另 一个线程获取了资源2上的写线程锁,并请求资源1上的读线程锁。如果不使用超时,这两个线程将出现死锁。
如果超时间隔过期并且没有授 予锁请求,则此方法通过引发 ApplicationException 将控制返回给调用线程。线程可以捕捉此异常并确定下一步要进行的操作。
值    说明
-1   Infinite.
0   无超时。
> 0  要等待的毫秒数。

手控同步:
1 Mutex
该类从WaitHandle派生
除了可以用于进程间同步
Metux非常类似于 Monitor.
当两个或更多线程需要同时访问一个共享资源时,系统需要使用同步机制来确保一次只有一个线程使用该资源。Mutex 是同步基元,它只向一个线程授予对共享资源的独占访问权。如果一个线程获取了互斥体,则要获取该互斥体的第二个线程将被挂起,直到第一个线程释放该互斥 体。
WaitOne 方法:请求互斥体的所属权。拥有互斥体的线程可以在对 Wait 的重复调用中请求相同的互斥体而不会阻塞其执行。
ReleaseMutex 方法:释放互斥体的所属权。如果线程在拥有互斥体期间正常终止,则互斥体状态设置为终止,并且下一个等待线程获得所属权。如果没有线程拥有互斥体,则互斥 体状态为终止。
public class Account
{
 int val ;
 Mutex m;
 public Account(){m=new Mutex(true,"test");}
 public int Read()
 {
  int iRet = 0;
  m.WaitOne();
  try
  {
   iRet = val;
  }
  finally
  {
   m.ReleaseMutex();
  }
  return iRet;
 }
 
 public void Write(int x)
 {
  m.WaitOne();
  try
  {
   val = x;
  }
  finally
  {
   m.ReleaseMutex();
  }
 }
}

2 ManualResetEvent类与AutoResetEvent类
该类从WaitHandle派生
该对象只 能拥有2种状态:有信号或无信号
Set和Reset方法返回一个BOOL,表示状态是否成功进行修改
把状态修改 成无信号,使用Reset方法,修改成有信号,使用Set方法
WaitOne方法:在有信号时不等待,无信号时等待。2个参数,第一 个是等待毫秒数,第二个BOOL,如果已经在上下文同步域想要退出,或者要重新获得同步上下文,就设置为True。
在 AutoResetEvent时,WaitOne会改变状态。使用ManualResetEvent时不会。

3 InterLocked
此类的方法可以防止可能在下列情况发生的错误:线程正在更新可由其他线程访问的变量时,计划程序切换上下文;或者两个线程在不同的处理器 上同时执行。此类的成员不引发异常。
Increment 和 Decrement 方法递增或递减变量并将结果值存储在单个操作中。在大多数计算机上,增加变量操作不是一个原子操作,需要执行下列步骤:
(1).将实例变量中的值加载到寄存器中。
(2).增加或减少该值。
(3).在实例变量中存储该值。
如果不使用 Increment 和 Decrement,线程会在执行完前两个步骤后被抢先。然后由另一个线程执行所有三个步骤。当第一个线程重新开始执行时,它改写实例变量中的值,造成第 二个线程执行增减操作的结果丢失。
Exchange 方法自动交换指定变量的值。CompareExchange 方法组合了两个操作:比较两个值以及根据比较的结果将第三个值存储在其中一个变量中。比较和交换操作按原子操作执行。
有InterLocked公开的Exchange和CompareExchange方法采用可以存储引用的Object类型的参数。但 是,类型安全要求将所有参数严格类型化为Object;不能对其中一个方法的调用中简单地将对象强制转换为Object,换言之,必须创建Object类 型变量,将自定义对象赋给该变量,然后传递该变量。
例子:
public class DemoInterLocked
{
Object _x;
public Object X
{
set
{
Object ovalue = value;
InterLocked.CompareExchange(ref _x , ovalue , null);
}
get
{
return _x;
}
}
}

//下面用Interlocked实现互斥的例子
using System ;
using System.Threading;
namespace DemoSyncResource
{
class Resource
{
ReaderWriterLock rwl = new ReaderWriterLock();

public void Read(Int32 threadNum)
{
rwl.AcquireReaderLock(Timeout.Infinite);
try
{
Console.WriteLine("开始读资源(Thread={0})", threadNum);
Thread.Sleep(250);
Console.WriteLine("读取资源结束(Thread={0})", threadNum);
}
finally
{
rwl.ReleaseReaderLock();
}
}

public void Write(Int32 threadNum)
{
rwl.AcquireWriterLock(Timeout.Infinite);
try
{
Console.WriteLine("开始写资源 (Thread={0})", threadNum);
Thread.Sleep(750);
Console.WriteLine("写资源结束 (Thread={0})", threadNum);
}
finally
{
rwl.ReleaseWriterLock();
}
}
}

class App
{
//临界资源
static Int32 numAsyncOps = 4;
//同步对象
static AutoResetEvent asyncAreDone = new AutoResetEvent(false);
//临界资源
static Resource res = new Resource();

public static void Main()
{
for (Int32 threadNum = 0 ;threadNum < 4 ; threadNum )
{
ThreadPool.QueueUserWorkItem(new WaitCallback(UpdateResource),threadNum);
}
asyncAreDone.WaitOne();
Console.WriteLine("所有操作都结束");
}

static void UpdateResource(object state)
{
Int32 threadNum = (Int32)state;
if ((threadNum % 2)!=0)
res.Read(threadNum);
else
res.Write(threadNum);
//利用Interlocked.Decrement互斥的修改临界资源
//每执行一个线程都将numAsyncOps减1
//如果numAsyncOps变为0,说明4个线程都执行完了
if(Interlocked.Decrement(ref numAsyncOps) == 0)
asyncAreDone.Set();
}
}
}

上下文同步:(使用SynchronizationAttribute类)
该类属于 命名空间System.EnterpriseServices
使用该类可以对对象进行简单的自动同步。.net把同步锁和对象自动关 联,调用方法前锁定对象,方法返回后释放对象。
其不自动处理静态对象和方法。
使用 System.EnterpriseAttribute编程的时候,使用该类十分方便。因为一个上下文中对象由COM+运行库组合在一起。
使用方法:
[SynchronizationAttribute (SynchronizationOption.Required)]
public class myclass{......}

静态变量和方法同步:(使用ThreadStaticAttribute类)
静态变 量只能有一个实例。如果同步一个静态变量或方法,锁就要应用于整个类上,其结果会使得其他对象不能使用此类的静态变量
带有 ThreadStaticAttribute的静态变量不会在不同线程之间共享,每个访问的线程都有静态变量或方法的一个副本。如果一个线程修改了变量, 另一个线程不能看到这些变化。
使用方法:
[System.ThreadStaticAttribute()]
public static xxx(){}

转载于:https://www.cnblogs.com/erik168/archive/2006/11/16/562351.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值