2011-02-16 3 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

+0

에 게시 시도 할 수 있습니다. 감사합니다 – Holoed

답변

0

내에서 간단한 포인트의 몇 :

1)가 컴파일되지 않습니다, 내가 뭔가를 놓친 게 뭐죠? 특정 C# 미리보기 또는 뭔가?

2) 중요한 병목 현상이 될 하나의 syncObject를 사용 중입니다. 본질적으로 모든 것을 다시 단일 스레드 응용 프로그램으로 돌려 놓습니다. 그렇게하는 쉬운 방법이 있습니다. 이 자동적 동시성은 상당한 성능 비용을 초래합니다.

3) 여기에 필드가 하나만있어 손상 될 수 있습니다. 왜 액세서리를 잠글 수 있습니까? 당신은 여전히 ​​그들에 대한 작전을 작성할 수 있습니다. 사실, 클래스 디자이너는 잠금과 동시성에주의해야합니다. 그러나 다른 한편으로는, 당신의 접근 방식을 사용하여 프로그래머는 당신의 작문 수업을 이해해야 할 것입니다. 나는 대부분의 사람들이 이미 그것을 알고 있기 때문에 정상적인 잠금으로 갈 것입니다.

재미있는 생각이지만, 아직까지 이런 식으로하는 것이 도움이되지 않으며 몇 가지 단점이 있습니다. 그러나 트랜잭션 메모리에 대해 많은 생각을하고 있습니다. 이것은 무언가로 이어질 수 있습니다.

GJ

+0

꺾쇠 괄호를 고정했습니다. 지금 컴파일해야합니다. – Holoed

관련 문제