avoid Race condition - BlockingCollection - c#

I'm using .NET 3.5 and need a slimmed version of a BlockingCollection (that doesn't necessarily need to be strong typed).
I've come up with the following which is more than enough for my needs in terms of features, but I think suffers from a race condition:
public class WuaBlockingCollection
{
private const int TimeoutInterval = 50;
private readonly Queue _queue = new Queue();
private readonly AutoResetEvent _event = new AutoResetEvent(false);
private readonly object _queueLock = new object();
public bool IsAddingComplete { get; private set; }
public void Add(object item)
{
lock (_queueLock)
{
if (IsAddingComplete)
throw new InvalidOperationException(
"The collection has been marked as complete with regards to additions.");
_queue.Enqueue(item);
}
_event.Set();
}
public object Take()
{
if (!TryTake(out var obj, Timeout.Infinite))
{
throw new InvalidOperationException(
"The collection argument is empty and has been marked as complete with regards to additions.");
}
return obj;
}
public bool TryTake(out object obj, int timeout)
{
var elapsed = 0;
var startTime = Environment.TickCount;
obj = null;
lock (_queueLock)
{
if (IsAddingComplete && _queue.Count == 0) return false;
}
do
{
var waitTime = timeout - elapsed;
if (waitTime > TimeoutInterval || timeout == Timeout.Infinite)
{
waitTime = TimeoutInterval;
}
if (_event.WaitOne(waitTime))
{
break;
}
} while (timeout == Timeout.Infinite || (elapsed = unchecked(Environment.TickCount - startTime)) < timeout);
if (timeout != Timeout.Infinite && elapsed >= timeout) return false;
var isQueueEmpty = false;
lock (_queueLock)
{
if (_queue.Count == 0)
{
return false;
}
obj = _queue.Dequeue();
if (_queue.Count > 0)
{
isQueueEmpty = true;
}
}
if (!isQueueEmpty)
{
_event.Set();
}
return true;
}
public void CompleteAdding()
{
lock (_queueLock)
{
IsAddingComplete = true;
}
_event.Set();
}
}
More specifically, in the TryTake() method around the if (!isQueueEmpty) part.
Basically in between isQueueEmpty being set and something being done with it's value another thread might do something that affects _queue.Count.
Theoretically only the Add() or CompleteAdding() should be able to do this (because multiple threads running TryTake() would be stuck at either the lock() or the _event.WaitOne()) but I'm not sure if this is either something to worry about nor how to actually fix it without putting the _event.Set() inside the lock itself which I believe might have adverse effects.
If the answer is to put the _event.Set() inside the lock, please clarify why this would not impact on the event and whether any further modifications are required.

Related

Problem with memory in Queue which works in several threads

My program works with a queue and a large file. I work with the queue in several threads and at some point there is OutOfMemoryException because of having too many objects Enqueued in the first thread in the queue. They do not manage to Dequeue in the second thread as fast as required.
P.S. I can use just the primitives of synchronyzing (Thread, Monitor)
I've already written a code which works with not very big data. I know that I can do Thread.Sleep (and this is works, I thried) when in my queue exists definite amount of objects. As far as I know it's not the best solution
class SynchronizedQueue
{
protected readonly object locker = new object();
protected Queue<BlockData> queue = new Queue<BlockData>();
public int Counter { get; set; }
public bool IsClose { get; set; }
public bool TryDequeue(out BlockData blockData)
{
lock (locker)
{
while (queue.Count == 0)
{
if (IsClose)
{
blockData = new BlockData();
return false;
}
Monitor.Wait(locker);
}
blockData = queue.Dequeue();
return true;
}
}
public void Close()
{
lock (locker)
{
IsClose = true;
Monitor.PulseAll(locker);
}
}
public void Enqueue(BlockData blockData)
{
lock (locker)
{
//That's what i want to avoid
if (Counter == 1000)
{
Thread.Sleep(240);
}
if (IsClose)
throw new InvalidOperationException("Work was canceled!");
while (blockData.Id != Counter)
Monitor.Wait(locker);
queue.Enqueue(blockData);
Counter++;
Monitor.PulseAll(locker);
}
}
}
What can you recommend for synchronizing Enqueue/Dequeue and avoid OutOfMemoryException?

Off-delay timer

Is there a way to write a safe one-second off-delay timer class in C# using exactly one System.Threading.Timer object?
Alternatively, what would be the simplest solution in general, assuming the input can get turned on and off a lot faster than once per second?
An off-delay timer could be described by this interface:
public interface IOffDelay
{
/// <summary>
/// May be set to any value from any thread.
/// </summary>
bool Input { get; set; }
/// <summary>
/// Whenever Input is true, Output is also true.
/// The Output is only false at startup
/// or after the Input has been continuously off for at least 1 second.
/// </summary>
bool Output { get; }
}
This is my first attempt:
public sealed class OffDelay : IOffDelay, IDisposable
{
public OffDelay()
{
timer = new Timer(TimerCallback, null, Timeout.Infinite, Timeout.Infinite);
}
public void Dispose()
{
timer.Dispose();
}
public bool Input
{
get
{
lock (locker)
return _input;
}
set
{
lock (locker)
{
if (value == _input)
return;
_input = value;
if (_input == false)
timer.Change(1000, Timeout.Infinite);
else
{
_output = true;
timer.Change(Timeout.Infinite, Timeout.Infinite);
}
}
}
}
private bool _input;
public bool Output
{
get
{
lock (locker)
return _output;
}
}
private bool _output;
private readonly Timer timer;
private readonly object locker = new object();
private void TimerCallback(object state)
{
lock (locker)
_output = false;
}
}
I can see that there is a race condition in this solution:
At the end of a one-second off period, the timer schedules the callback to run.
Someone quickly sets and resets the input, restarting the timer.
The callback now finally runs, checks the input and sets the output to false even though it should be true for another second.
Edit
Peter Duniho provided the correct answer, but it turns out I'm terrible at asking the right question. The OffDelay class should also do some operation when the output changes to false. Here is the modified code adapting Peter's basic principle:
public sealed class OffDelay : IOffDelay, IDisposable
{
public OffDelay()
{
timer = new Timer(TimerCallback, null, Timeout.Infinite, Timeout.Infinite);
}
public void Dispose()
{
timer.Dispose();
}
public bool Input
{
get
{
lock (locker)
return _input;
}
set
{
lock (locker)
{
if (value == _input)
return;
_input = value;
if (_input == true)
_output = true;
else
{
stopwatch.Restart();
if (!timerRunning)
timer.Change(1000, Timeout.Infinite);
}
}
}
}
private bool _input;
public bool Output
{
get
{
lock (locker)
return _output;
}
}
private bool _output;
private readonly object locker = new object();
private readonly Timer timer;
private readonly Stopwatch stopwatch = new Stopwatch();
private bool timerRunning;
private void TimerCallback(object state)
{
lock (locker)
{
if (_input == true)
timerRunning = false;
else
{
var remainingTimeMs = 1000 - stopwatch.ElapsedMilliseconds;
if (remainingTimeMs > 0)
timer.Change(remainingTimeMs, Timeout.Infinite);
else
{
_output = false;
timerRunning = false;
DoSomething();
}
}
}
}
private void DoSomething()
{
// ...
}
}
Without a good Minimal, Complete, and Verifiable code example that clearly illustrates the question, including showing exactly what the context is and what constraints might exist, it's impossible to know for sure what answer would work for you.
But based on what you've included in your question, I would change your implementation so it doesn't rely on the timer:
public sealed class OffDelay : IOffDelay
{
public bool Input
{
get { lock (locker) return _input; }
set
{
lock (locker)
{
if (value == _input)
return;
_input = value;
_lastInput = DateTime.UtcNow;
}
}
}
private bool _input;
public bool Output
{
get { lock (locker) return (DateTime.UtcNOw - _lastInput).TotalSeconds < 1; }
}
private DateTime _lastInput;
}
Note that the above is susceptible to clock changes on the computer. If you have a need to work independently of the clock, you can replace DateTime.UtcNow with a Stopwatch instance, call Reset() on each change to the Input property, and use the Elapsed property of the Stopwatch to determine the length of time since last input.

Synchronization issues: everything seems correct, but

I wrote a multithreaded application for .NET and in a very important portion of code I have the following:
public class ContainerClass {
private object list_lock;
private ArrayList list;
private object init_lock = new object();
private ThreadClass thread;
public void Start() {
lock(init_lock) {
if (thread == null) {
thread = new ThreadClass();
...
}
}
}
public void Stop() {
lock(init_lock) {
if (thread != null) {
thread.processList(0);
thread.finish();
thread.waitUntilFinished();
thread = null;
} else {
throw new ApplicationException("Assertion failed - already stopped.");
}
...
}
}
private class ThreadedClass {
private ContainerClass container;
private Thread thread;
private bool finished;
private bool actually_finished;
public ThreadedClass(ContainerClass container) {
this.container = container;
thread = new Thread(run);
thread.IsBackground = true;
thread.Start();
}
private void run() {
bool local_finished = false;
while (!local_finished) {
ArrayList to_process = null;
lock (container.list_lock) {
if (container.list.Count > 0) {
to_process = new ArrayList();
to_process.AddRange(container.list);
}
}
if (to_process == null) {
// Nothing to process so wait
lock (this) {
if (!finished) {
try {
Monitor.Wait(this);
} catch (ThreadInterruptedException) {
}
}
}
} else if (to_process.Count > 0) {
// Something to process, so go ahead and process the journals,
int sz = to_process.Count;
// For all elements
for (int i = 0; i < sz; ++i) {
// Pick the lowest element to process
object obj = to_process[i];
try {
// process the element...
...
} catch (IOException e) {
...
// If there is an error processing the best thing to do is finish
lock (this) {
finished = true;
}
}
}
}
lock (this) {
local_finished = finished;
// Remove the elements that we have just processed.
if (to_process != null) {
lock (container.list_lock) {
int sz = to_process.Count;
for (int i = 0; i < sz; ++i) {
container.list.RemoveAt(0);
}
}
}
// Notify any threads waiting
Monitor.PulseAll(this);
}
}
lock (this) {
actually_finished = true;
Monitor.PulseAll(this);
}
}
public void waitUntilFinished() {
lock (this) {
try {
while (!actually_finished) {
Monitor.Wait(this);
}
} catch (ThreadInterruptedException e) {
throw new ApplicationException("Interrupted: " + e.Message);
}
}
}
public void processList(int until_size) {
lock (this) {
Monitor.PulseAll(this);
int sz;
lock (container.list_lock) {
sz = container.list.Count;
}
// Wait until the sz is smaller than 'until_size'
while (sz > until_size) {
try {
Monitor.Wait(this);
} catch (ThreadInterruptedException ) {
}
lock (container.list_lock) {
sz = container.list.Count;
}
}
}
}
}
}
As you can see, the thread waits until the collection is empty but it seems that the synchronization clashes forbids the thread to enter at the point (the only one in the whole code) where an element is removed from the collection list in the ContainerClass.
This clash provokes the code to never return and the application to continue running if the method processList is called with the value of until_size of 0.
I beg any better developer than me (and I guess there are a lot out there) to help me fixing this small piece of code, since I really can't understand why the list isn't decremented...
Thank you very much from the bottom of my heart.
PS. I would like to underline that the code works perfectly for all the time: the only situation in which it brakes it's when calling thread.processList(0) from ContainerClass.Stop().
Could the problem be that you are locking the ThreadClass object itself rather than a synchronizing object?
Try adding another private variable to lock on:
private static readonly object lockObject = new object()
and replace all the calls of lock(this) with lock(lockObject)
MSDN clearly advises against what your doing:
In general, avoid locking on a public
type, or instances beyond your code's
control. The common constructs lock
(this), lock (typeof (MyType)), and
lock ("myLock") violate this
guideline:
lock (this) is a problem if the instance can be accessed publicly.
Edit:
I think I see a deadlock condition. If you call run() when there are no objects to process, or you get to no objects to process, you lock(this), then call Monitor.Wait(this) and the thread waits:
if (to_process == null) {
// Nothing to process so wait
lock (this) { /* nothing's going to get this lock again until Monitor.PulseAll(this) is called from somewhere */
if (!finished) {
try {
Monitor.Wait(this); /* thread is waiting for Pulse(this) or PulseAll(this) */
} catch (ThreadInterruptedException) {
}
}
}
}
If you are in this condition when you call Container.Stop(), when ThreadProcess.processList(int) is called, you call lock(this) again, which can't enter the section because the run() method still has the lock:
lock (this) { /* run still holds this lock, waiting for PulseAll(this) to be called */
Monitor.PulseAll(this); /* this isn't called so run() never continues */
int sz;
lock (container.list_lock) {
sz = container.list.Count;
}
So, Monitor.PulseAll() can't be called to free the waiting thread in the run() method to exit the lock(this) area, so they are deadlocked waiting on each other. Right?
I think you should try to explain better what you actually want to achieve.
public void processList(int until_size) {
lock (this) {
Monitor.PulseAll(this);
This looks very strange as you should call the Monitor.Pulse when changing the lock state and not when beginning with locking.
Where are you creating the worker threads - this section is not clear as I see only Thread.Start()?
Btw I would advise you to look at PowerCollections - maybe you find what you need there.

Is there a synchronization class that guarantee FIFO order in C#?

What is it and how to use?
I need that as I have a timer that inserts into DB every second, and I have a shared resource between timer handler and the main thread.
I want to gurantee that if the timer handler takes more than one second in the insertion the waited threads should be executed in order.
This is a sample code for my timer handler:
private void InsertBasicVaraibles(object param)
{
try
{
DataTablesMutex.WaitOne();//mutex for my shared resources
//insert into DB
}
catch (Exception ex)
{
//Handle
}
finally
{
DataTablesMutex.ReleaseMutex();
}
}
But currently the mutex does not guarantee any order.
You'll need to write your own class to do this, I found this example (pasted because it looks as though the site's domain has lapsed):
using System.Threading;
public sealed class QueuedLock
{
private object innerLock;
private volatile int ticketsCount = 0;
private volatile int ticketToRide = 1;
public QueuedLock()
{
innerLock = new Object();
}
public void Enter()
{
int myTicket = Interlocked.Increment(ref ticketsCount);
Monitor.Enter(innerLock);
while (true)
{
if (myTicket == ticketToRide)
{
return;
}
else
{
Monitor.Wait(innerLock);
}
}
}
public void Exit()
{
Interlocked.Increment(ref ticketToRide);
Monitor.PulseAll(innerLock);
Monitor.Exit(innerLock);
}
}
Example of usage:
QueuedLock queuedLock = new QueuedLock();
try
{
queuedLock.Enter();
// here code which needs to be synchronized
// in correct order
}
finally
{
queuedLock.Exit();
}
Source via archive.org
Just reading Joe Duffy's "Concurrent Programming on Windows" it sounds like you'll usually get FIFO behaviour from .NET monitors, but there are some situations where that won't occur.
Page 273 of the book says: "Because monitors use kernel objects internally, they exhibit the same roughly-FIFO behavior that the OS synchronization mechanisms also exhibit (described in the previous chapter). Monitors are unfair, so if another thread sneaks in and acquires the lock before an awakened waiting thread tries to acquire the lock, the sneaky thread is permitted to acquire the lock."
I can't immediately find the section referenced "in the previous chapter" but it does note that locks have been made deliberately unfair in recent editions of Windows to improve scalability and reduce lock convoys.
Do you definitely need your lock to be FIFO? Maybe there's a different way to approach the problem. I don't know of any locks in .NET which are guaranteed to be FIFO.
You should re-design your system to not rely on the execution order of the threads. For example, rather than have your threads make a DB call that might take more than one second, have your threads place the command they would execute into a data structure like a queue (or a heap if there is something that says "this one should be before another one"). Then, in spare time, drain the queue and do your db inserts one at a time in the proper order.
There is no guaranteed order on any built-in synchronisation objects: http://msdn.microsoft.com/en-us/library/ms684266(VS.85).aspx
If you want a guaranteed order you'll have to try and build something yourself, note though that it's not as easy as it might sound, especially when multiple threads reach the synchronisation point at (close to) the same time. To some extent the order they will be released will always be 'random' since you cannot predict in which order the point is reached, so does it really matter?
Actually the answers are good, but I solved the problem by removing the timer and run the method (timer-handler previously) into background thread as follows
private void InsertBasicVaraibles()
{
int functionStopwatch = 0;
while(true)
{
try
{
functionStopwatch = Environment.TickCount;
DataTablesMutex.WaitOne();//mutex for my shared resources
//insert into DB
}
catch (Exception ex)
{
//Handle
}
finally
{
DataTablesMutex.ReleaseMutex();
}
//simulate the timer tick value
functionStopwatch = Environment.TickCount - functionStopwatch;
int diff = INSERTION_PERIOD - functionStopwatch;
int sleep = diff >= 0 ? diff:0;
Thread.Sleep(sleep);
}
}
Follow up on Matthew Brindley's answer.
If converting code from
lock (LocalConnection.locker) {...}
then you could either do a IDisposable or do what I did:
public static void Locking(Action action) {
Lock();
try {
action();
} finally {
Unlock();
}
}
LocalConnection.Locking( () => {...});
I decided against IDisposable because it would creates a new invisible object on every call.
As to reentrancy issue I modified the code to this:
public sealed class QueuedLock {
private object innerLock = new object();
private volatile int ticketsCount = 0;
private volatile int ticketToRide = 1;
ThreadLocal<int> reenter = new ThreadLocal<int>();
public void Enter() {
reenter.Value++;
if ( reenter.Value > 1 )
return;
int myTicket = Interlocked.Increment( ref ticketsCount );
Monitor.Enter( innerLock );
while ( true ) {
if ( myTicket == ticketToRide ) {
return;
} else {
Monitor.Wait( innerLock );
}
}
}
public void Exit() {
if ( reenter.Value > 0 )
reenter.Value--;
if ( reenter.Value > 0 )
return;
Interlocked.Increment( ref ticketToRide );
Monitor.PulseAll( innerLock );
Monitor.Exit( innerLock );
}
}
In case anyone needs Matt's solution in F#
type internal QueuedLock() =
let innerLock = Object()
let ticketsCount = ref 0
let ticketToRide = ref 1
member __.Enter () =
let myTicket = Interlocked.Increment ticketsCount
Monitor.Enter innerLock
while myTicket <> Volatile.Read ticketToRide do
Monitor.Wait innerLock |> ignore
member __.Exit () =
Interlocked.Increment ticketToRide |> ignore
Monitor.PulseAll innerLock
Monitor.Exit innerLock
Elaborating on Matt Brindley's great answer so that it works with the using statement:
public sealed class QueuedLockProvider
{
private readonly object _innerLock;
private volatile int _ticketsCount = 0;
private volatile int _ticketToRide = 1;
public QueuedLockProvider()
{
_innerLock = new object();
}
public Lock GetLock()
{
return new Lock(this);
}
private void Enter()
{
int myTicket = Interlocked.Increment(ref _ticketsCount);
Monitor.Enter(_innerLock);
while (true)
{
if (myTicket == _ticketToRide)
{
return;
}
else
{
Monitor.Wait(_innerLock);
}
}
}
private void Exit()
{
Interlocked.Increment(ref _ticketToRide);
Monitor.PulseAll(_innerLock);
Monitor.Exit(_innerLock);
}
public class Lock : IDisposable
{
private readonly QueuedLockProvider _lockProvider;
internal Lock(QueuedLockProvider lockProvider)
{
_lockProvider = lockProvider;
_lockProvider.Enter();
}
public void Dispose()
{
_lockProvider.Exit();
}
}
}
Now use it like this:
QueuedLockProvider _myLockProvider = new QueuedLockProvider();
// ...
using(_myLockProvider.GetLock())
{
// here code which needs to be synchronized
// in correct order
}
NOTE: The examples provided are susceptible to Deadlocks.
Example:
QueuedLock queuedLock = new QueuedLock();
void func1()
{
try
{
queuedLock.Enter();
fubc2()
}
finally
{
queuedLock.Exit();
}
}
void func2()
{
try
{
queuedLock.Enter(); //<<<< DEADLOCK
}
finally
{
queuedLock.Exit();
}
}
Re. optional solution (inc. an optional IDisposable usage):
public sealed class QueuedLock
{
private class SyncObject : IDisposable
{
private Action m_action = null;
public SyncObject(Action action)
{
m_action = action;
}
public void Dispose()
{
lock (this)
{
var action = m_action;
m_action = null;
action?.Invoke();
}
}
}
private readonly object m_innerLock = new Object();
private volatile uint m_ticketsCount = 0;
private volatile uint m_ticketToRide = 1;
public bool Enter()
{
if (Monitor.IsEntered(m_innerLock))
return false;
uint myTicket = Interlocked.Increment(ref m_ticketsCount);
Monitor.Enter(m_innerLock);
while (true)
{
if (myTicket == m_ticketToRide)
return true;
Monitor.Wait(m_innerLock);
}
}
public void Exit()
{
Interlocked.Increment(ref m_ticketToRide);
Monitor.PulseAll(m_innerLock);
Monitor.Exit(m_innerLock);
}
public IDisposable GetLock()
{
if (Enter())
return new SyncObject(Exit);
return new SyncObject(null);
}
}
Usage:
QueuedLock queuedLock = new QueuedLock();
void func1()
{
bool isLockAquire = false;
try
{
isLockAquire = queuedLock.Enter();
// here code which needs to be synchronized in correct order
}
finally
{
if (isLockAquire)
queuedLock.Exit();
}
}
or:
QueuedLock queuedLock = new QueuedLock();
void func1()
{
using (queuedLock.GetLock())
{
// here code which needs to be synchronized in correct order
}
}

How to prevent deadlocks in the following C# code?

The following C# class is used in a multithreaded enviroment. I removed very much of the actual code. The problem occurs when calling MethodA and MethodB almost simultaneously. The order of the lock in the IsDepleted property doesn't solves the problem. Removing lock(WaitingQueue) from the IsDepleted property solves the deadlock, but this solution causes a problem when another thread adds/removes an item from the WaitingQueue between the WaitingQueue.Count == 0 and Processing.Count == 0 statements.
using System.Collections.Generic;
class Example
{
bool IsDepleted
{
get
{
lock (Processing)
{
lock (WaitingQueue)
{
return WaitingQueue.Count == 0
&& Processing.Count == 0;
}
}
}
}
private readonly List<object> Processing = new List<object>();
private readonly Queue<object> WaitingQueue = new Queue<object>();
public void MethodA(object item)
{
lock (WaitingQueue)
{
if (WaitingQueue.Count > 0)
{
if (StartItem(WaitingQueue.Peek()))
{
WaitingQueue.Dequeue();
}
}
}
}
public void MethodB(object identifier)
{
lock (Processing)
{
Processing.Remove(identifier);
if (!IsDepleted)
{
return;
}
}
//Do something...
}
bool StartItem(object item)
{
//Do something and return a value
}
}
It depends if you want a quick fix or a rigorous fix.
A quick fix would be just to use one lock object in all cases.
e.g. private readonly object _lock = new object();
And then just lock on that. However, depending on your situation, that may impact performance more than you can accept.
I.e. your code would become this:
using System.Collections.Generic;
class Example
{
private readonly object _lock = new object();
bool IsDepleted
{
get
{
lock (_lock)
{
return WaitingQueue.Count == 0
&& Processing.Count == 0;
}
}
}
private readonly List<object> Processing = new List<object>();
private readonly Queue<object> WaitingQueue = new Queue<object>();
public void MethodA(object item)
{
lock (_lock)
{
if (WaitingQueue.Count > 0)
{
if (StartItem(WaitingQueue.Peek()))
{
WaitingQueue.Dequeue();
}
}
}
}
public void MethodB(object identifier)
{
lock (_lock)
{
Processing.Remove(identifier);
if (!IsDepleted)
{
return;
}
}
//Do something...
}
bool StartItem(object item)
{
//Do something and return a value
}
}
Take the Processing lock in method A and the WaitingQueue lock in method B (in other words, make it look like the first block of code). That way, you always take the locks in the same order and you'll never deadlock.
Simplify your code and use only a single object to lock on. You could also replace your locks with:
Monitor.TryEnter(Processing,1000)
this will give you a 1 second timeout. So essentially:
if (Monitor.TryEnter(Processing, 1000))
{
try
{
//do x
}
finally
{
Monitor.Exit(Processing);
}
}
Now you won't stop the deadlock but you can handle the case where you don't get a lock.

Categories

Resources