none
Interlocked 问题 RRS feed

  • 问题

  • class Account {
    
    	private Object lockObject = new Object();
    
    	int balance;
    
    	Random r = new Random();
    
    
    
    	public Account(int initial) {
    
    		balance = initial;
    
    	}
    
    
    
    	/* 使用 Lock 示例 */
    
    	private int UseLock(int amount) {
    
    		lock (lockObject) {	// 只要 lock 语句存在,语句块就是临界区并且 balance 永远不会是负数。
    
    			if (balance >= amount) {
    
    				Console.WriteLine("--------------------------------------------------------------------------");
    
    				Console.WriteLine("Balance 在临界区退出之前的值为 : " + balance);
    
    				Console.WriteLine("Amount 在临界区退出之前的值为 : -" + amount);
    
    				balance = balance - amount;
    
    				Console.WriteLine("Balance 在临界区退出之后的值为 : " + balance);
    
    				Console.WriteLine("--------------------------------------------------------------------------");
    
    				return amount;
    
    			} else {
    
    				return 0; // transaction rejected
    
    			}
    
    		}
    
    	}
    
    
    
    	/* 使用 Monitor 示例 */
    
    	private int UseMonitor(int amount) {
    
    		try {
    
    			/* Monitor的第一种实现 : 不限制时间 */
    
    			//Monitor.Enter(thisLockObject);
    
    
    
    			/* Monitor的第一种实现 : 限制时间为 30 秒 */
    
    			if (Monitor.TryEnter(lockObject, 3000)) {
    
    				if (balance >= amount) {
    
    					Console.WriteLine("--------------------------------------------------------------------------");
    
    					Console.WriteLine("Balance 在临界区退出之前的值为 : " + balance);
    
    					Console.WriteLine("Amount 在临界区退出之前的值为 : -" + amount);
    
    					balance = balance - amount;
    
    					Console.WriteLine("Balance 在临界区退出之后的值为 : " + balance);
    
    					Console.WriteLine("--------------------------------------------------------------------------");
    
    					return amount;
    
    				}
    
    			}
    
    		} finally {
    
    			Monitor.Exit(lockObject);	// 不管是正常还是异常,都释放锁的对象.
    
    		}
    
    
    
    		return 0; // transaction rejected
    
    	}
    
    
    
    	/* 使用 Interlocked 示例 */
    
    	private int UseInterlocked(int amount) {
    
    		if (balance >= amount) {
    
    			int oldBalance = balance;
    
    			int location = balance - amount;
    
    			int value = balance - amount;
    
    
    
    			if (Interlocked.CompareExchange(ref location, value, location) == location) {	// 条件为真时,表明这是一个正常的执行过程.
    
    				Console.WriteLine("--------------------------------------------------------------------------");
    
    				Console.WriteLine("Balance 在临界区退出之前的值为 : " + oldBalance);
    
    				Console.WriteLine("Amount 在临界区退出之前的值为 : -" + amount);
    
    				Console.WriteLine("Balance 在临界区退出之后的值为 : " + location);
    
    				Console.WriteLine("--------------------------------------------------------------------------");
    
    			}
    
    
    
    			return amount;
    
    		} else {
    
    			return 0; // transaction rejected
    
    		}
    
    	}
    
    
    
    	private int Withdraw(int amount) {
    
    		if (balance < 0) { throw new Exception("Balance 为负数!"); }
    
    
    
    		//return UseLock(amount);			// 使用 Lock 示例
    
    		//return UseMonitor(amount);		// 使用 Monitor 示例
    
    		return UseInterlocked(amount);	// 使用 Interlocked 示例
    
    	}
    
    
    
    	public void DoTransactions() {
    
    		for (int i = 0; i < 100; i++) {
    
    			Withdraw(r.Next(1, 100));
    
    		}
    
    	}
    
    }
    
    
    
    class Program {
    
    	static void Main(string[] args) {
    
    		Thread[] threads = new Thread[10];
    
    		Account acc = new Account(1000);
    
    
    
    		for (int i = 0; i < 10; i++) {
    
    			Thread t = new Thread(new ThreadStart(acc.DoTransactions));
    
    			threads[i] = t;
    
    		}
    
    
    
    		for (int i = 0; i < 10; i++) {
    
    			threads[i].Start();
    
    		}
    
    
    
    		Console.Read();
    
    	}
    
    }
    
    

    截取 Lock 部分值:
    --------------------------------------------------------------------------
    Balance 在临界区退出之前的值为 :  1000
    Amount  在临界区退出之前的值为 : -20
    Balance 在临界区退出之后的值为 :  980
    --------------------------------------------------------------------------

    截取 Interlocked.CompareExchange 部分值:
    Balance 在临界区退出之后的值为 :  913
    --------------------------------------------------------------------------
    Balance 在临界区退出之后的值为 :  949
    --------------------------------------------------------------------------
    --------------------------------------------------------------------------
    --------------------------------------------------------------------------
    Balance 在临界区退出之前的值为 :  1000
    --------------------------------------------------------------------------
    --------------------------------------------------------------------------
    Balance 在临界区退出之前的值为 :  1000
    --------------------------------------------------------------------------
    Balance 在临界区退出之前的值为 :  1000
    Amount  在临界区退出之前的值为 : -51
    Balance 在临界区退出之前的值为 :  1000
    --------------------------------------------------------------------------
    Balance 在临界区退出之前的值为 :  1000
    Amount  在临界区退出之前的值为 : -82
    Balance 在临界区退出之前的值为 :  1000
    --------------------------------------------------------------------------
    Amount  在临界区退出之前的值为 : -72
    --------------------------------------------------------------------------
    Balance 在临界区退出之前的值为 :  1000
    Amount  在临界区退出之前的值为 : -84
    Balance 在临界区退出之后的值为 :  916
    --------------------------------------------------------------------------

    为什么 Interlocked 会出现这样的结果,如果我想 Interlocked 的代码实现与 Lock 类似结果的代码,我应该如何做?
    或者说 Interlocked  可否实现类似 Lock 类似结果?


    2011年6月2日 2:12

答案

  • dear

    Interlocked 類別也是可以達到執行緒同步的功能

    http://msdn.microsoft.com/zh-tw/library/system.threading.interlocked%28VS.80%29.aspx

     

    你得關注 Increment 和 Decrement、Exchange 、CompareExchange 等方法


    秘訣無它,唯勤而已 http://www.dotblogs.com.tw/yc421206/
    • 已标记为答案 钱仔 2011年6月2日 17:52
    2011年6月2日 5:47
  • Interlocked 静态类型是用来做一些原子 (atomic) 操作的,比如,大家知道,在 32 位机器上,大于 4 个字节的加法不是原子的,比如,两个 long 相加,结果可能不是希望的。为了让一些操作能具备原子性 (也就是,要么这些操作全部做完,成功,要么都没做),.NET 就提供了 Interlocked 类型。

    Interlocked 上有几个非常有用的方法,如 CompareExchange,Add 等。但请注意,原子性和锁匙不同的东西,虽然,Interlocked 可以用来实现加锁的功能,但它的本质不是用来让您去做线程同步代码的。最近 MSDN 上有一篇很好的文章,推荐给大家看看。

    Atomicity, volatility and immutability are different, part two
    http://blogs.msdn.com/b/ericlippert/archive/2011/05/31/atomicity-volatility-and-immutability-are-different-part-two.aspx


    Mark Zhou
    • 已标记为答案 钱仔 2011年6月2日 17:52
    2011年6月2日 6:57

全部回复

  • dear

    Interlocked 類別也是可以達到執行緒同步的功能

    http://msdn.microsoft.com/zh-tw/library/system.threading.interlocked%28VS.80%29.aspx

     

    你得關注 Increment 和 Decrement、Exchange 、CompareExchange 等方法


    秘訣無它,唯勤而已 http://www.dotblogs.com.tw/yc421206/
    • 已标记为答案 钱仔 2011年6月2日 17:52
    2011年6月2日 5:47
  • Interlocked 静态类型是用来做一些原子 (atomic) 操作的,比如,大家知道,在 32 位机器上,大于 4 个字节的加法不是原子的,比如,两个 long 相加,结果可能不是希望的。为了让一些操作能具备原子性 (也就是,要么这些操作全部做完,成功,要么都没做),.NET 就提供了 Interlocked 类型。

    Interlocked 上有几个非常有用的方法,如 CompareExchange,Add 等。但请注意,原子性和锁匙不同的东西,虽然,Interlocked 可以用来实现加锁的功能,但它的本质不是用来让您去做线程同步代码的。最近 MSDN 上有一篇很好的文章,推荐给大家看看。

    Atomicity, volatility and immutability are different, part two
    http://blogs.msdn.com/b/ericlippert/archive/2011/05/31/atomicity-volatility-and-immutability-are-different-part-two.aspx


    Mark Zhou
    • 已标记为答案 钱仔 2011年6月2日 17:52
    2011年6月2日 6:57