代码改变世界

C# 线程手册 第三章 使用线程 .NET 同步策略

2012-02-02 20:45  DanielWise  阅读(3014)  评论(3编辑  收藏  举报

公共语言架构提供了三种策略来同步访问实例和静态方法以及实例属性,这三种策略是:

  1. 同步上下文

  2. 同步代码区域

  3. 手动同步

同步上下文

上下文是一系列对象集合在执行时常见的属性或者使用规范。可以被添加的上下文属性包括同步,线程关联以及事务。简而言之,一个上下文是由一些相似的对象组成。在同步策略中,我们使用SynchronizationAttribute 类来为ContextBoundObject 对象提供简单、原子化同步。上下文中绑定到上下文规则上的对象被称作上下文绑定对象。.NET 自动地使用一个同步锁来关联这个对象,在每次方法调用之前锁住并在方法返回时释放锁(允许其他竞争线程访问对象)。这是对生产力的巨大提高,因为线程同步和并发管理是一个开发人员所需面对的最困难的任务(没有之一)。

SynchronizationAttribute 类对那些没有手动处理同步问题经验的开发人员来说是很有用的,因为它囊括了属性所应用到的类的实例变量,实例方法以及实例字段。它不处理静态字段和静态方法的同步。如果你不得不同步特殊代码块的话那么它也不起作用;为了便于使用你不得不同步整个对象。使用System.EnterpriseServices编程时SynchronizationAttribute 会非常有用,因为它可以将属于一个上下文(或者一个事务)的对象通过COM+运行时组合到一起。

回到我们的Account例子,我们可以通过使用SynchronizationAttribute 来让我们使用伪代码实现的Account类支持线程安全。下面是具体的例子:

/*************************************
/* Copyright (c) 2012 Daniel Dong
 * 
 * Author:Daniel Dong
 * Blog:  www.cnblogs.com/danielWise
 * Email: guofoo@163.com
 * 
 */

using System;
using System.Collections.Generic;
using System.Text;
using System.EnterpriseServices;

namespace SimpleThread
{
    [SynchronizationAttribute(SynchronizationOption.Required)]
    public class Account : ContextBoundObject
    {
        public ApprovedOrNot Withdraw(Amount)
        {
            //1. Check the Account Balance
            //2. Update the Account with the new balance
            //3. Send approval to the ATM
        }
    }
}

 

SynchronizationAttribute 类有两个构造函数;一个无参构造函数和一个以SynchronizationOption枚举作为参数的构造函数。我们使用默认的无参构造函数,SynchronizationOption枚举的默认值是SynchronizationOption.Required. 其他的枚举值是Disabled, NotSupported, RequiredNew 和 Supported. 下面列举出了这些选项。

Synchronization

 

同步代码区域

第二个同步策略主要关注特定代码区域。这些特定的代码区域是方法中改变对象状态或者更新其他资源(数据库或者文件)的关键代码片段。在这部分我们将看看Monitor 和 ReaderWriterLock 类。

Monitors

Monitors 使用Monitor.Enter() 方法来获得一个锁并使用锁来同步代码部分,然后使用Monitor.Exit()方法来释放锁。一个锁的概念通常用来解释Monitor类。一个线程获得一个锁,而其他线程一直等待锁被释放。一旦锁被一个代码区域获得,你可以在Monitor.Enter() 和Monitor.Exit() 代码块中使用如下方法:

  Wait() - 这个对象在一个对象上释放锁并阻塞当前线程直到它获得到锁

  Pulse() - 这个方法通知在队列中等待的指定线程对象的状态已经发生改变

  PulseAll() - 这个方法通知在队列中等待的所有线程对象的状态已经发生改变

 

下一篇我们将会介绍Monitor.Enter() 和 Monitor.Exit() 方法…