2011-02-16 25 views
1

我正在玩弄LINQ,並提出了以下利用C#Monadic語法編寫鎖的想法。這看起來太簡單了,所以我想讓我把它發佈到StackOverflow上,看看有沒有人可以很快地發現這種方法的任何主要問題。使用LINQ的可組合的鎖。任何人都可以看到這個問題嗎?

如果你在原子實現中註釋鎖,你會看到賬戶被破壞。

這個想法是關於能夠在沒有明確鎖定的情況下撰寫賬戶操作。

using System; 
using System.Collections.Generic; 
using System.Linq; 

namespace AtomicLinq 
{ 
    public static class AccountCombinators 
    { 
     public static IAtomic <Unit> TransferAndReverse(this Account accA, 
                 Account accB, 
                 double amount) 
     { 
      return from a in accA.TransferTo(accB, amount) 
        from b in accB.TransferTo(accA, amount) 
        select new Unit(); 
     } 

     public static IAtomic<Unit> TransferTo(this Account accA, 
               Account accB, 
               double amount) 
     { 
      return from a in accA.Withdraw(amount) 
        from b in accB.Deposit(amount) 
        select new Unit(); 
     } 

     public static IAtomic<double> Withdraw(this Account acc, double amount) 
     { 
      return Atomic.Create(() => acc.Amount -= amount); 
     } 

     public static IAtomic<double> Deposit(this Account acc, double amount) 
     { 
      return Atomic.Create(() => acc.Amount += amount); 
     } 
    } 

    static class Program 
    { 
     static void Main(string[] args) 
     { 
      var accA = new Account("John") { Amount = 100.0 }; 
      var accB = new Account("Mark") { Amount = 200.0 }; 

      var syncObject = new object(); 
      Enumerable.Range(1, 100000).AsParallel().Select(_ => accA.TransferAndReverse(accB, 100).Execute(syncObject)).Run(); 

      Console.WriteLine("{0} {1}", accA, accA.Amount); 
      Console.WriteLine("{0} {1}", accB, accB.Amount); 

      Console.ReadLine(); 
     }   
    }  

    public class Account 
    { 
     public double Amount { get; set; } 
     private readonly string _name; 

     public Account(string name) 
     { 
      _name = name; 
     } 

     public override string ToString() 
     { 
      return _name; 
     } 
    } 

    #region Atomic Implementation 

    public interface IAtomic<T> 
    { 
     T Execute(object sync); 
    } 

    public static class Atomic 
    { 
     public static IAtomic<T> Create<T>(Func<object, T> f) 
     { 
      return new AnonymousAtomic<T>(f); 
     } 

     public static IAtomic<T> Create<T>(Func<T> f) 
     { 
      return Create(_ => f()); 
     } 

     public static IAtomic<T> Aggregate<T>(this IEnumerable<IAtomic<T>> xs) 
     { 
      return xs.Aggregate((x, y) => from a in x 
              from b in y 
              select b); 
     } 

     public static IAtomic<K> SelectMany<T, V, K>(this IAtomic<T> m, Func<T, IAtomic<V>> f, Func<T, V, K> p) 
     { 
      return Create(sync => 
           { 
            var t = m.Execute(sync); 
            var x = f(t); 
            return p(t, x.Execute(sync)); 
           }); 
     } 
    } 

    public class AnonymousAtomic<T> : IAtomic<T> 
    { 
     private readonly Func<object, T> _func; 

     public AnonymousAtomic(Func<object, T> func) 
     { 
      _func = func; 
     } 

     public T Execute(object sync) 
     { 
      lock (sync) // Try to comment this lock you'll see that the accounts get corrupted 
       return _func(sync); 
     } 
    } 

    #endregion Atomic Implementation 
} 



+0

你可以嘗試張貼codereview.stackexchange – flesh 2011-02-16 20:53:31

+0

我只是做了。謝謝 – Holoed 2011-02-16 21:08:46

回答

0

從我幾個簡單的要點:

1)不編譯,我失去的東西嗎?具體的C#預覽什麼的?

2)您正在使用一個syncObject,它將成爲一個主要瓶頸。從本質上講,您將整個事件轉換回單線程應用程序。有更簡單的方法來做到這一點。這種自動併發性帶來相當大的性能成本。

3)這裏只有一個字段可能被損壞,爲什麼不鎖定它的訪問器呢?你仍然可以對它們進行操作。誠然,類設計師必須注意鎖定和併發性。但另一方面,使用你的方法,程序員必須理解你的組合類。因爲大多數人都知道它,所以我會正常鎖定。

這是一個有趣的想法,但我不認爲這樣做的好處還有一些缺點。但是有很多關於事務內存的想法等等,這可能導致某些事情。

GJ

相關問題