4

기존 앱 스레드를 안전하게 만들어야합니다. (아래 참조) 상황에 따라 비즈니스 개체의 전체 그래프에 하나의 ReaderWriterLock을 사용하기로 결정했습니다. 모든 메소드/속성을 다음과 같이해야합니다.NET에서 선언적 스레드 안전

public int MyReadOperation(string inputParam) 
{ 
    rwLock.AcquireReaderLock(10000); 
    try 
    { 
     // do all read operations 
     ... 
    } 
    finally 
    { 
     rwLock.ReleaseReaderLock(); 
    } 
} 

public void MyWriteOperation(string input) 
{ 
    rwLock.AcquireWriterLock(10000); 
    try 
    { 
     // do all write operations 
     ... 
    } 
    finally 
    { 
     rwLock.ReleaseWriterLock(); 
    } 

} 

하지만 커버하는 방법의 엄청난 금액을 가지고 있고 복사/붙여 넣기의 아이디어에서 기겁을하고있다. MethodImplAttribute에서 영감을 , 나는 행동하라 위의 코드로 동안이 같은 코드를 선호하는 것 : 스레드 실행을 중단 할 수있는 방법이 있나요

[ReadOperation] 
public int MyReadOperation(string inputParam) 
{ 
    // do all read operations 
    ... 
} 

[WriteOperation]  
public void MyWriteOperation(string input) 
{ 
    // do all write operations 
    ... 
} 

전/속성이나 방법에 입력하고 스레드를 추가 한 후 - 안전 예방 조치? 또는 어떻게 든 C#의 기능적 언어 기능을 활용하여 메서드의 생산 본문을 일반 "ReaderWriterLock"프레임 "aquiring"에 포함 할 수 있습니까?

배경 비트 : 나는 데이터 캐리어 비즈니스 오브젝트는 .NET Remoting을 통해 노출되는 프로젝트를 진행하고

. 그러나 이러한 데이터 클래스는 직렬화 가능하지 않지만 MarshalByRef-s입니다. 이는 모든 클라이언트가 실제로 동일한 비즈니스 객체를 읽고 쓰는 것을 의미합니다. 이것은 바뀔 수 없으며, 돌로 새겨 져 있습니다. 스레드 안전성에 대한 희망은 이러한 원격 비즈니스 객체가 원격 클라이언트 (클라이언트가 많은 목록을 반복한다고 생각하는)에게 읽기 전용이고 모든 쓰기 작업이 전용 외관으로 잘 분리되어 있다는 것입니다. 희소 한 쓰기 및 빈번한 읽기가 예상됩니다. 비즈니스 개체는 고도로 연결되어 있으며 매우 그래픽 적입니다.

+0

정말 새로운 일을해야합니다 =) ... –

+0

MSDN (http://msdn.microsoft.com/en-us/library/system.threading.readerwriterlock.aspx)은 ReaderWriterLockSlim ReaderWriterLock 대신. –

답변

4

먼저 앤드류가 PostSharp을 가리키고 있습니다. 그의 대답에 따라, 나는이 마지막 것을 끝내었다.

[Serializable] 
public class ReadOperationAttribute : PostSharp.Laos.OnMethodInvocationAspect 
{ 
    public override void OnInvocation(MethodInvocationEventArgs eventArgs) 
    { 
     ReaderWriterLock rwLock = GetLock(); 
     rwLock.AcquireReaderLock(10000); 
     try { eventArgs.Proceed(); } 
     finally { rwLock.ReleaseReaderLock();} 
    } 
} 
public class Foo 
{ 
    [ReadOperation] 
    public string Bar 
    { 

     get { return "stuff"; } 
     set { Console.WriteLine(value); } 
    } 

    [ReadOperation] 
    public void Test(string input) 
    { 
     Console.WriteLine(input); 
    } 
} 

정확히 내가 질문에서 표현한 것이며 완벽하게 디버그 가능합니다.

[assembly: ReadOperation(AttributeTargetElements=MulticastTargets.Method, 
AttributeTargetTypes="MyNamespace.*")] 

이 우리가 모든 메소드/속성을 장식하지 않는 방법으로, 그러나 한 번 어셈블리에서이 속성을 배치, 우리 모두 braket : 우리는 전체 어셈블리에 대한 속성을 선언하는 경우 우리는 그것을 훨씬 더 유용 할 수 있습니다 ReaderWriterLock으로 메소드/속성.

또한 Andrew가 지적했듯이 Microsoft는 .NET3.5 이상을 사용하는 경우 ReaderWriterLockSlim을 사용하는 것이 좋습니다.

+0

자신의 도움이 아닌 실제 도움을 받아 들였어야합니다. – dpan

+0

아니요! 나는 다른 독자를 돕기 위해 적절한 대답을 받아 들여야한다! 나는 그의 값진 공헌으로 앤드류에게 적절한 신용을 주었다. (Btw, 내 자신의 대답을 받아 들여, 보상 포인트를 얻지 못한다) –

+1

Meh. 나는 그 점을 위해 그것에 있지 않다. :) –

6

나는 PostSharp을 사용하는 것과 같은 것을 할 것입니다.

추가 빌드 단계로 실행되고 해당 MSIL을 삽입하지만 원하는대로 수행합니다. PostSharp 속성 정의는 다음과 같을 것입니다 (정확한 구현에 따라 다름). 위에서 설명한대로 사용할 수 있습니다.

public sealed class ReadOperationAttribute : OnMethodBoundaryAspect 
{ 
    // not quite sure how you manage your lock, so put this dummy method in. 
    ReaderWriterLock _rwLock = ReaderWriterLock.GetCorrectReaderWriterLock(); 

    [ThreadStatic] 
    static bool _isLocked; 

    public override void OnEntry(MethodExecutionEventArgs e) 
    { 
    try 
    { 
     _rwLock.AcquireReaderLock(10000); 
     _isLocked = true; 
    } 
    catch 
    { 
     _isLocked = false; 
     throw; 
    } 
    } 

    public override void OnExit(MethodExecutionEventArgs e) 
    {  
     if (_isLocked) 
     { 
      _rwLock.ReleaseReaderLock(); 
      _isLocked = false; 
     } 
    } 
} 

public sealed class WriteOperationAttribute : OnMethodBoundaryAspect 
{ 
    // not quite sure how you manage your lock, so put this dummy method in. 
    ReaderWriterLock _rwLock = ReaderWriterLock.GetCorrectReaderWriterLock(); 

    [ThreadStatic] 
    static bool _isLocked; 

    public override void OnEntry(MethodExecutionEventArgs e) 
    { 
    try 
    { 
     _rwLock.AcquireWriterLock(10000); 
     _isLocked = true; 
    } 
    catch 
    { 
     _isLocked = false; 
     throw; 
    } 
    } 

    public override void OnExit(MethodExecutionEventArgs e) 
    { 
     if (_isLocked) 
     { 
      _rwLock.ReleaseReaderLock(); 
      _isLocked = false; 
     } 
    } 
} 

편집 : 주소 관련 문제로 업데이트됩니다. (Untested;)) 또한 질문에 대한 주석에서 Microsoft recommendsReaderWriterLock보다 우선하여 ReaderWriterLockSlim을 사용합니다.

+0

정확히 무엇을 할 것입니다. :) +1 –

+0

왜 고마워요 :) –

+0

이것은 내가 좋아하는 답변이지만, 작지만 중요한 세부 사항으로 인해 충분하지 않습니다. OnEntry를 덮어 쓰면 "try"섹션 내부로 잠금 장치를 가져옵니다. 잠금 획득이 실패하고 예외가 발생하면 "finally"섹션이 계속 실행됩니다. –

1

빌드 후 단계를 사용하는 것이 좋은 해결책 일 수 있습니다. 순수 코드에서는 다음과 같이 ReaderWriterLock에 확장 메서드를 만들 것입니다.

public static void ReadLock(this ReaderWriterLock l, Action f) { 
    l.AquireReaderLock(); 
    try { f(); } 
    finally { l.ReleaseReaderLock(); } 
} 

그리고 하나는 쓰기 용입니다. 자물쇠가 완전히 글로벌 인 경우 정적 방법을 만들 수도 있습니다. 그런 다음 코드는 훨씬 덜 성가신 같습니다으로 동기 필요하지 않는 방법의 부분으로 동기되지 않도록

public void DoSomething() { 
    theLock.ReadLock(() => { 
    // Existing code 
    }); 
} 

이 세밀하게되는 이점이있다. 그러나 여전히 각 방법을 변경해야합니다. 다행스럽게도 그것들은 상대적으로 작으며 변경을 끝내는 모든 잠금 코드는 적어도 한 곳에서 발생합니다.