2

I have one thread, that is sending data stored in a buffer of type List< string> via tcp. Another thread is writing into the buffer. As I am not very familiar with c# I'd like to know how I should use lock or Mutex correctly.

This is the code I'd like to use eventually:

 while(buffer.isLocked()) { buffer.wait(); } buffer.lockBuffer(); buffer.add(tcpPacket); buffer.unlockBuffer(); buffer.notify(); 

This is my current code. I hope someone can help me complete it.

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() { //... } } 

3 Answers 3

4

It would be better if you use System.Collections.Concurrent.BlockingCollection. It doesn't require an external sync.

For those who don't use 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; } } } 
Sign up to request clarification or add additional context in comments.

11 Comments

He might not be using .NET 4.0
Please note that using lock(this) is usually a bad practice. What if an external class locks on your BlockingQueue?
thanks for the code! I have some problems with the SemaphoreSlim objects though. I assume it is because I am using .NET 3.5. Do you know how I could replace them?
@AC-CII Is this a problem? Then declare a local object to lock. This was just a sample to show how a blocking queue can be implemented. Would this be reason to downvote?
@Pedro, replace them with Semaphore , Wait with WaitOne and remove Count property
|
2

The following code is not thread-safe. If two threads are entering this method at the same time, both might pass the if condition successfully.

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

You simply might want to do something like this:

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

I don't think you're doing something sophisticated that requires more than the simple to use lock-statement.

Comments

1

I wouldn't use Mutexes since I suppose you aren't dealing with multiple processes synchronization. Locks are pretty fine and simpler to implement:

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 // } } } 

The usage is obviously (as you requested):

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

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.