2011-10-20 2 views
2

하나의 스레드가 있습니다.이 스레드는 List < 문자열> tcp를 통해 버퍼에 저장된 데이터를 전송합니다. 다른 스레드가 버퍼에 쓰고 있습니다. C#에 대해 잘 알고 있지는 않지만 잠금 또는 뮤텍스를 올바르게 사용해야하는 방법을 알고 싶습니다. 뮤텍스 사용 방법

내가 결국 사용하려는 코드 :

while(buffer.isLocked()) 
{ 
    buffer.wait(); 
} 

    buffer.lockBuffer(); 
    buffer.add(tcpPacket); 
    buffer.unlockBuffer(); 
    buffer.notify(); 

이 내 현재 코드입니다. 누군가가 나를 도와 줄 수 있기를 바랍니다.

public class Buffer 
{ 
    private Mutex mutex; 
    private List<string> buffer; 
    private bool locked = false; 

    public Buffer() 
    { 
     mutex = new Mutex(false); 
     buffer = new List<string>(); 
    } 

    public bool isLocked() 
    { 
     return locked; 
    } 

    public void lockBuffer() 
    { 
     if (!locked) 
     { 
      //... 
      locked = true; 
     } 
    } 

    public void unlockBuffer() 
    { 
     if(locked) 
     { 
      mutex.ReleaseMutex(); 
      locked = false; 
     } 
    } 

    public void wait() 
    { 
     mutex.WaitOne(); 
    } 

    public void notify() 
    { 
     //... 
    } 
} 

답변

4

System.Collections.Concurrent.BlockingCollection을 사용하는 것이 좋습니다. 외부 동기화가 필요 없습니다. 난 당신이 여러 프로세스 동기화 처리되지 않은 가정 때문에 내가 뮤텍스를 사용하지 않을 4.0

using System; 
using System.Collections.Generic; 
using System.Threading; 

namespace MyCollections 
{ 
    public class BlockingQueue<T> : IDisposable 
    { 
     Queue<T> _Queue = new Queue<T>(); 
     SemaphoreSlim _ItemsInQueue = null; 
     SemaphoreSlim _FreeSlots = null; 
     int _MaxItems = -1; 

     public BlockingQueue(int maxItems=Int32.MaxValue) 
     { 
      _MaxItems = maxItems; 
      _ItemsInQueue = new SemaphoreSlim(0, maxItems); 
      _FreeSlots = new SemaphoreSlim(maxItems, maxItems); 
     } 

     public void Dispose() 
     { 
      if (_ItemsInQueue != null) _ItemsInQueue.Dispose(); 
      if (_FreeSlots != null) _FreeSlots.Dispose(); 
     } 

     public int Count 
     { 
      get { return _ItemsInQueue.CurrentCount; } 
     } 


     public void Add(T item) 
     { 
      if(_MaxItems != Int32.MaxValue) _FreeSlots.Wait(); 
      lock (this) 
      { 
       _Queue.Enqueue(item); 
       _ItemsInQueue.Release(); 
      } 
     } 


     public T Take() 
     { 
      T item = default(T); 
      _ItemsInQueue.Wait(); 
      lock (this) 
      { 
       item = _Queue.Dequeue(); 
       if (_MaxItems != Int32.MaxValue) _FreeSlots.Release(); 
      } 
      return item; 
     } 
    } 
} 
+0

그는 .NET 4.0을 사용하지 않을 수도 있습니다. – Aren

+3

'lock (this) '을 사용하는 것은 나쁜 습관입니다. 외부 클래스가 당신의'BlockingQueue'를 잠그면 어떨까요? –

+0

코드를 보내 주셔서 감사합니다! SemaphoreSlim 객체에 몇 가지 문제가 있습니다. 내가 .NET 3.5를 사용하고 있기 때문에 그것이 있다고 가정합니다. 내가 그들을 어떻게 대체 할 수 있는지 아십니까? – Pedro

1

를 사용하지 않는 사람들을 위해

. 잠금 구현하기가 매우 미세하고 간단 : (당신이 요청에 따라)

class Buffer 
{ 
    private readonly object syncObject = new object(); 
    private readonly List<string> buffer = new List<string>(); 

    public void AddPacket(string packet) 
    { 
     lock (syncObject) 
     { 
      buffer.Add(packet); 
     } 
    } 

    public void Notify() 
    { 
     // Do something, if needed lock again here 
     // lock (syncObject) 
     // { 
     //  Notify Implementation 
     // } 
    } 
} 

사용법은 분명히 :

var myBuffer = new Buffer(); 
myBuffer.Add("Hello, World!"); 
myBuffer.Notify(); 
2

다음 코드는 스레드로부터 안전하지 않습니다. 2 개의 thread가이 메소드에 동시에 들어가는 경우, 양쪽 모두는 if 조건을 성공적으로 건네 줄 가능성이 있습니다.

public void lockBuffer() 
{ 
    if (!locked) 
    { 
     //... 
     locked = true; 
    } 
} 

당신은 단순히 다음과 같은 일을 수행 할 수 있습니다 :

lock (_sycnObject) 
{ 
    buffer.lockBuffer(); 
    buffer.add(tcpPacket); 
    buffer.unlockBuffer(); 
    buffer.notify(); 
} 

난 당신이 잠금 문을 사용하여 간단한보다 더 필요 정교한 일을하고 있다고 생각하지 않습니다.