I'm working on multithread app and there is part of code which sholud be run only by one thread same time. Nothing complicated. I use lock to synchronize it. It's working in life system but I would like to write unit test to check if only one thread is in the critical section. I wrote one, it was working but it stops :)
I can't figure out how to write a test it in proper way. I use NSubstitute to create mocks.
Class to test:
public interface IMultiThreadClass
{
void Go();
}
public class Lock02 : IMultiThreadClass
{
private readonly IProcessor _processor;
private readonly string _threadName;
private static readonly object Locker = new Object();
public Lock02(IProcessor processor, string threadName)
{
_processor = processor;
_threadName = threadName;
}
public void Go()
{
//critical section
lock (Locker)
{
_processor.Process(_threadName);
}
}
}
Test:
[TestMethod()]
public void Run_Test()
{
//Only one thread should run Processor.Process, but we allow max 2 threads to catch locking erorrs
SemaphoreSlim semaphore = new SemaphoreSlim(1, 2);
//Semaphore to synchronize asserts
SemaphoreSlim synchroSemaphore = new SemaphoreSlim(0, 1);
IProcessor procesor = Substitute.For<IProcessor>();
procesor.When(x => x.Process(Arg.Any<string>())).Do(y =>
{
//increment counter to check if method was called
Interlocked.Increment(ref _counter);
//release synchro semaphore
synchroSemaphore.Release();
//stop thread and wait for release
semaphore.Wait();
});
Lock02 locker1 = new Lock02(procesor, "1");
Lock02 locker2 = new Lock02(procesor, "2");
Lock02 locker3 = new Lock02(procesor, "3");
Task.Run(() => locker1.Go());
Task.Run(() => locker2.Go());
Task.Run(() => locker3.Go());
//ASSERT
//Thread.Sleep(1000);
synchroSemaphore.Wait();
Assert.AreEqual(1, _counter);
semaphore.Release(1);
synchroSemaphore.Wait();
Assert.AreEqual(2, _counter);
semaphore.Release(1);
synchroSemaphore.Wait();
Assert.AreEqual(3, _counter);
semaphore.Release(1);
}
A possible (simple but not bulletproof) way is to spawn some threads/tasks in the unit test, each fetching and temporarily storing an int variable (possibly static), waiting for a bit (delay), incrementing the value and writing it back to the variable. Without thread synchronization (lock), many if not all threads will grab the same number and it will not be equal (as it should) to the number of threads/tasks.
This is not bulletproof since there is still a race condition making it not reproducible (the smelly code is the 50 ms delay), although it seems (to me) very unlikely for all treads to wait for each other in the perfect way and produce the right result.
I consider this being a smelly workaround, but it is simple and works.
[TestMethod]
public async Task APossibleTest()
{
int importantNumber = 0;
var proc = Substitute.For<IProcessor>();
proc.WhenForAnyArgs(processor => processor.Process(Arg.Any<string>()))
.Do(callInfo =>
{
int cached = importantNumber;
// Wait for other threads to fetch the number too (if they were not synchronized).
Thread.Sleep(TimeSpan.FromMilliseconds(50));
// This kind of incrementation will check the thread synchronization.
// Using a thread-safe Interlocked or other here does not make sense.
importantNumber = cached + 1;
});
var locker = new Locker(proc, "da horror");
// Create 10 tasks all attempting to increment the important number.
Task[] tasks =
Enumerable
.Range(0, 10)
// You could create multiple lockers here (with their own processors).
.Select(i => Task.Run(() => locker.Go()))
.ToArray();
await Task.WhenAll(tasks);
Assert.AreEqual(10, importantNumber, "Exactly 10 increments were expected since we have 10 tasks.");
}
Related
We have an old 3rd party system (let's call it Junksoft® 95) that we interface with via PowerShell (it exposes a COM object) and I'm in the process of wrapping it in a REST API (ASP.NET Framework 4.8 and WebAPI 2). I use the System.Management.Automation nuget package to create a PowerShell in which I instantiate Junksoft's COM API as a dynamic object that I then use:
//I'm omitting some exception handling and maintenance code for brevity
powerShell = System.Management.Automation.PowerShell.Create();
powerShell.AddScript("Add-Type -Path C:\Path\To\Junksoft\Scripting.dll");
powerShell.AddScript("New-Object Com.Junksoft.Scripting.ScriptingObject");
dynamic junksoftAPI = powerShell.Invoke()[0];
//Now we issue commands to junksoftAPI like this:
junksoftAPI.Login(user,pass);
int age = junksoftAPI.GetAgeByCustomerId(custId);
List<string> names = junksoftAPI.GetNames();
This works fine when I run all of this on the same thread (e.g. in a console application). However, for some reason this usually doesn't work when I put junksoftAPI into a System.Web.Caching.Cache and use it from different controllers in my web app. I say ususally because this actually works when ASP.NET happens to give the incoming call to the thread that junksoftAPI was created on. If it doesn't, Junksoft 95 gives me an error.
Is there any way for me to make sure that all interactions with junksoftAPI happen on the same thread?
Note that I don't want to turn the whole web application into a single-threaded application! The logic in the controllers and elswhere should happen like normal on different threads. It should only be the Junksoft interactions that happen on the Junksoft-specific thread, something like this:
[HttpGet]
public IHttpActionResult GetAge(...)
{
//finding customer ID in database...
...
int custAge = await Task.Run(() => {
//this should happen on the Junksoft-specific thread and not the next available thread
var cache = new System.Web.Caching.Cache();
var junksoftAPI = cache.Get(...); //This has previously been added to cache on the Junksoft-specific thread
return junksoftAPI.GetAgeByCustomerId(custId);
});
//prepare a response using custAge...
}
You can create your own singleton worker thread to achieve this. Here is the code which you can plug it into your web application.
public class JunkSoftRunner
{
private static JunkSoftRunner _instance;
//singleton pattern to restrict all the actions to be executed on a single thread only.
public static JunkSoftRunner Instance => _instance ?? (_instance = new JunkSoftRunner());
private readonly SemaphoreSlim _semaphore;
private readonly AutoResetEvent _newTaskRunSignal;
private TaskCompletionSource<object> _taskCompletionSource;
private Func<object> _func;
private JunkSoftRunner()
{
_semaphore = new SemaphoreSlim(1, 1);
_newTaskRunSignal = new AutoResetEvent(false);
var contextThread = new Thread(ThreadLooper)
{
Priority = ThreadPriority.Highest
};
contextThread.Start();
}
private void ThreadLooper()
{
while (true)
{
//wait till the next task signal is received.
_newTaskRunSignal.WaitOne();
//next task execution signal is received.
try
{
//try execute the task and get the result
var result = _func.Invoke();
//task executed successfully, set the result
_taskCompletionSource.SetResult(result);
}
catch (Exception ex)
{
//task execution threw an exception, set the exception and continue with the looper
_taskCompletionSource.SetException(ex);
}
}
}
public async Task<TResult> Run<TResult>(Func<TResult> func, CancellationToken cancellationToken = default(CancellationToken))
{
//allows only one thread to run at a time.
await _semaphore.WaitAsync(cancellationToken);
//thread has acquired the semaphore and entered
try
{
//create new task completion source to wait for func to get executed on the context thread
_taskCompletionSource = new TaskCompletionSource<object>();
//set the function to be executed by the context thread
_func = () => func();
//signal the waiting context thread that it is time to execute the task
_newTaskRunSignal.Set();
//wait and return the result till the task execution is finished on the context/looper thread.
return (TResult)await _taskCompletionSource.Task;
}
finally
{
//release the semaphore to allow other threads to acquire it.
_semaphore.Release();
}
}
}
Console Main Method for testing:
public class Program
{
//testing the junk soft runner
public static void Main()
{
//get the singleton instance
var softRunner = JunkSoftRunner.Instance;
//simulate web request on different threads
for (var i = 0; i < 10; i++)
{
var taskIndex = i;
//launch a web request on a new thread.
Task.Run(async () =>
{
Console.WriteLine($"Task{taskIndex} (ThreadID:'{Thread.CurrentThread.ManagedThreadId})' Launched");
return await softRunner.Run(() =>
{
Console.WriteLine($"->Task{taskIndex} Completed On '{Thread.CurrentThread.ManagedThreadId}' thread.");
return taskIndex;
});
});
}
}
}
Output:
Notice that, though the function was launched from the different threads, some portion of code got always executed always on the same context thread with ID: '5'.
But beware that, though all the web requests are executed on independent threads, they will eventually wait for some tasks to get executed on the singleton worker thread. This will eventually create a bottle neck in your web application. This is anyway your design limitation.
Here is how you could issue commands to the Junksoft API from a dedicated STA thread, using a BlockingCollection class:
public class JunksoftSTA : IDisposable
{
private readonly BlockingCollection<Action<Lazy<dynamic>>> _pump;
private readonly Thread _thread;
public JunksoftSTA()
{
_pump = new BlockingCollection<Action<Lazy<dynamic>>>();
_thread = new Thread(() =>
{
var lazyApi = new Lazy<dynamic>(() =>
{
var powerShell = System.Management.Automation.PowerShell.Create();
powerShell.AddScript("Add-Type -Path C:\Path\To\Junksoft.dll");
powerShell.AddScript("New-Object Com.Junksoft.ScriptingObject");
dynamic junksoftAPI = powerShell.Invoke()[0];
return junksoftAPI;
});
foreach (var action in _pump.GetConsumingEnumerable())
{
action(lazyApi);
}
});
_thread.SetApartmentState(ApartmentState.STA);
_thread.IsBackground = true;
_thread.Start();
}
public Task<T> CallAsync<T>(Func<dynamic, T> function)
{
var tcs = new TaskCompletionSource<T>(
TaskCreationOptions.RunContinuationsAsynchronously);
_pump.Add(lazyApi =>
{
try
{
var result = function(lazyApi.Value);
tcs.SetResult(result);
}
catch (Exception ex)
{
tcs.SetException(ex);
}
});
return tcs.Task;
}
public Task CallAsync(Action<dynamic> action)
{
return CallAsync<object>(api => { action(api); return null; });
}
public void Dispose() => _pump.CompleteAdding();
public void Join() => _thread.Join();
}
The purpose of using the Lazy class is for surfacing a possible exception during the construction of the dynamic object, by propagating it to the callers.
...exceptions are cached. That is, if the factory method throws an exception the first time a thread tries to access the Value property of the Lazy<T> object, the same exception is thrown on every subsequent attempt.
Usage example:
// A static field stored somewhere
public static readonly JunksoftSTA JunksoftStatic = new JunksoftSTA();
await JunksoftStatic.CallAsync(api => { api.Login("x", "y"); });
int age = await JunksoftStatic.CallAsync(api => api.GetAgeByCustomerId(custId));
In case you find that a single STA thread is not enough to serve all the requests in a timely manner, you could add more STA threads, all of them running the same code (private readonly Thread[] _threads; etc). The BlockingCollection class is thread-safe and can be consumed concurrently by any number of threads.
If you did not say that was a 3rd party tool, I would have asumed it is a GUI class. For practical reasons, it is a very bad idea to have multiple threads write to them. .NET enforces a strict "only the creating thread shall write" rule, from 2.0 onward.
WebServers in general and ASP.Net in particular use a pretty big thread pool. We are talking 10's to 100's of Threads per Core. That means it is really hard to nail any request down to a specific Thread. You might as well not try.
Again, looking at the GUI classes might be your best bet. You could basically make a single thread with the sole purpose of immitating a GUI's Event Queue. The Main/UI Thread of your average Windows Forms application, is responsible for creating every GUI class instance. It is kept alive by polling/processing the event queue. It ends onlyx when it receies a cancel command, via teh Event Queue. Dispatching just puts orders into that Queue, so we can avoid Cross-Threading issues.
First, this is from something much bigger and yes, I could completely avoid this using await under normal/other circumstances. For anyone interested, I'll explain below.
To track how many tasks I still have left before my program continues, I've built the following:
A counter:
private static int counter;
Some method:
public static void Test()
{
List<Task> tasks = new List<Task>();
for (int i = 0; i < 10000; i++)
{
TaskCompletionSource<object> tcs = new TaskCompletionSource<object>();
var task = DoTaskWork();
task.ContinueWith(t => // After DoTaskWork
{
// [...] Use t's Result
counter--; // Decrease counter
tcs.SetResult(null); // Finish the task that the UI or whatever is waiting for
});
tasks.Add(tcs.Task); // Store tasks to wait for
}
Task.WaitAll(tasks.ToArray()); // Wait for all tasks that actually only finish in the ContinueWith
Console.WriteLine(counter);
}
My super heavy work to do:
private static Task DoTaskWork()
{
counter++; // Increase counter
return Task.Delay(500);
}
Now, interestingly I do not receive the number 0 at the end when looking at counter. Instead, the number varies with each execution. Why is this? I tried various tests, but cannot find the reason for the irregularity. With the TaskCompletionSource I believed this to be reliable. Thanks.
Now, for anyone that is interested in why I do this:
I need to create loads of tasks without starting them. For this I need to use the Task constructor (one of its rare use cases). Its disadvantage to Task.Run() is that it cannot handle anything with await and that it needs a return type from the Task to properly run (hence the null as result). Therefore, I need a way around that. Other ideas welcome...
Well. I am stupid. Just 5 minutes in, I realize that.
I just did the same while locking a helper object before changing the counter in any way and now it works...
private static int counter;
private static object locker = new object();
// [...]
task.ContinueWith(t =>
{
lock(locker)
counter--;
tcs.SetResult(null);
});
// [...]
private static Task DoTaskWork()
{
lock (locker)
counter++;
return Task.Delay(500);
}
I need to create loads of tasks without starting them ... Therefore, I need a way around that. Other ideas welcome...
So, if I read it correct you want to build a list of tasks without actually run them on creation. You could do that by building a list of Func<Task> objects you invoke when required:
async Task Main()
{
// Create list of work to do later
var tasks = new List<Func<Task>>();
// Schedule some work
tasks.Add(() => DoTaskWork(1));
tasks.Add(() => DoTaskWork(2));
// Wait for user input before doing work to demonstrate they are not started right away
Console.ReadLine();
// Execute and wait for the completion of the work to be done
await Task.WhenAll(tasks.Select(t => t.Invoke()));
Console.WriteLine("Ready");
}
public async Task DoTaskWork(int taskNr)
{
await Task.Delay(100);
Console.WriteLine(taskNr);
}
This will work, even if you use Task.Run like this:
public Task DoTaskWork(int taskNr)
{
return Task.Run(() =>
{
Thread.Sleep(100); Console.WriteLine(taskNr);
});
}
It this is not want you want can you elaborate more about the tasks you want to create?
I have a method called WaitForAction, which takes an Action delegate and executes it in a new Task. The method blocks until the task completes or until a timeout expires. It uses ManualResetEvent to wait for timeout/completion.
The following code shows an attempt to test the method in a multi-threaded environment.
class Program
{
public static void Main()
{
List<Foo> list = new List<Foo>();
for (int i = 0; i < 10; i++)
{
Foo foo = new Foo();
list.Add(foo);
foo.Bar();
}
SpinWait.SpinUntil(() => list.Count(f => f.finished || f.failed) == 10, 2000);
Debug.WriteLine(list.Count(f => f.finished));
}
}
public class Foo
{
public volatile bool finished = false;
public volatile bool failed = false;
public void Bar()
{
Task.Factory.StartNew(() =>
{
try
{
WaitForAction(1000, () => { });
finished = true;
}
catch
{
failed = true;
}
});
}
private void WaitForAction(int iMsToWait, Action action)
{
using (ManualResetEvent waitHandle = new ManualResetEvent(false))
{
Task.Factory.StartNew(() =>
{
action();
waitHandle.SafeSet();
});
if (waitHandle.SafeWaitOne(iMsToWait) == false)
{
throw new Exception("Timeout");
}
}
}
}
As the Action is doing nothing I would expect the 10 tasks started by calling Foo.Bar 10 times to complete well within the timeout. Sometimes this happens, but usually the program takes 2 seconds to execute and reports that only 2 instances of Foo 'finished' without error. In other words, 8 calls to WaitForAction have timed out.
I'm assuming that WaitForAction is thread safe, as each call on a Task-provided thread has its own stack. I have more or less proved this by logging the thread ID and wait handle ID for each call.
I realise that this code presented is a daft example, but I am interested in the principle. Is it possible for the task scheduler to be scheduling a task running the action delegate to the same threadpool thread that is already waiting for another action to complete? Or is there something else going on that I've missed?
Task.Factory utilizes the ThreadPool by default. With every call to WaitHandle.WaitOne, you block a worker thread. The .Net 4/4.5 thread pool starts with a small number of worker threads depending on your hardware platform (e.g., 4 on my machine) and it re-evaluates the pool size periodically (I believe it is every 1 second), creating new workers if necessary.
Since your program blocks all worker threads, and the thread pool doesn't grow fast enough, your waithandles timeout as you saw.
To confirm this, you can either 1) increase the timeouts or 2) increase the beginning thread pool size by adding the following line to the beginning of your program:
ThreadPool.SetMinThreads(32, 4);
then you should see the timeouts don't occur.
I believe your question was more academic than anything else, but you can read about a better implementation of a task timeout mechanism here, e.g.
var task = Task.Run(someAction);
if (task == await Task.WhenAny(task, Task.Delay(millisecondsTimeout)))
await task;
else
throw new TimeoutException();
I have a instance of a class that is accessed from several threads. This class take this calls and add a tuple into a database. I need this to be done in a serial manner, as due to some db constraints, parallel threads could result in an inconsistent database.
As I am new to parallelism and concurrency in C#, I did this:
private BlockingCollection<Task> _tasks = new BlockingCollection<Task>();
public void AddDData(string info)
{
Task t = new Task(() => { InsertDataIntoBase(info); });
_tasks.Add(t);
}
private void InsertWorker()
{
Task.Factory.StartNew(() =>
{
while (!_tasks.IsCompleted)
{
Task t;
if (_tasks.TryTake(out t))
{
t.Start();
t.Wait();
}
}
});
}
The AddDData is the one who is called by multiple threads and InsertDataIntoBase is a very simple insert that should take few milliseconds.
The problem is that, for some reason that my lack of knowledge doesn't allow me to figure out, sometimes a task is been called twice! It always goes like this:
T1
T2
T3
T1 <- PK error.
T4
...
Did I understand .Take() completely wrong, am I missing something or my producer/ consumer implementation is really bad?
Best Regards,
Rafael
UPDATE:
As suggested, I made a quick sandbox test implementation with this architecture and as I was suspecting, it does not guarantee that a task will not be fired before the previous one finishes.
So the question remains: how to properly queue tasks and fire them sequentially?
UPDATE 2:
I simplified the code:
private BlockingCollection<Data> _tasks = new BlockingCollection<Data>();
public void AddDData(Data info)
{
_tasks.Add(info);
}
private void InsertWorker()
{
Task.Factory.StartNew(() =>
{
while (!_tasks.IsCompleted)
{
Data info;
if (_tasks.TryTake(out info))
{
InsertIntoDB(info);
}
}
});
}
Note that I got rid of Tasks as I'm relying on synced InsertIntoDB call (as it is inside a loop), but still no luck... The generation is fine and I'm absolutely sure that only unique instances are going to the queue. But no matter I try, sometimes the same object is used twice.
I think this should work:
private static BlockingCollection<string> _itemsToProcess = new BlockingCollection<string>();
static void Main(string[] args)
{
InsertWorker();
GenerateItems(10, 1000);
_itemsToProcess.CompleteAdding();
}
private static void InsertWorker()
{
Task.Factory.StartNew(() =>
{
while (!_itemsToProcess.IsCompleted)
{
string t;
if (_itemsToProcess.TryTake(out t))
{
// Do whatever needs doing here
// Order should be guaranteed since BlockingCollection
// uses a ConcurrentQueue as a backing store by default.
// http://msdn.microsoft.com/en-us/library/dd287184.aspx#remarksToggle
Console.WriteLine(t);
}
}
});
}
private static void GenerateItems(int count, int maxDelayInMs)
{
Random r = new Random();
string[] items = new string[count];
for (int i = 0; i < count; i++)
{
items[i] = i.ToString();
}
// Simulate many threads adding items to the collection
items
.AsParallel()
.WithDegreeOfParallelism(4)
.WithExecutionMode(ParallelExecutionMode.ForceParallelism)
.Select((x) =>
{
Thread.Sleep(r.Next(maxDelayInMs));
_itemsToProcess.Add(x);
return x;
}).ToList();
}
This does mean that the consumer is single threaded, but allows for multiple producer threads.
From your comment
"I simplified the code shown here, as the data is not a string"
I assume that info parameter passed into AddDData is a mutable reference type. Make sure that the caller is not using the same info instance for multple calls since that reference is captured in Task lambda .
Based on the trace that you provided the only logical possibility is that you have called InsertWorker twice (or more). There are thus two background threads waiting for items to appear in the collection and occasionally they both manage to grab an item and begin executing it.
I need a simple data structure with these requirements:
it should behave like a queue,
all the enqueue operations should be atomic.
I have very limited experience with multithreading, but this is what I came up to:
public class Tickets
{
private ConcurrentQueue<uint> _tickets;
public Tickets(uint from, uint to)
{
Initialize(from, to);
}
private readonly object _lock = new object();
public void Initialize(uint from, uint to)
{
lock(_lock)
{
_tickets = new ConcurrentQueue<uint>();
for (uint i = from; i <= to; i++)
{
_tickets.Enqueue(i);
}
}
}
public uint Dequeue()
{
uint number;
if (_tickets.TryDequeue(out number))
{
return number;
}
throw new ArgumentException("Ticket queue empty!");
}
}
First question: is this code ok?
Secod question: how can I unit test this class (for instance with two threads which are perfoming dequeue operation periodically on the queue with elements (1, 2, 3, 4, 5, 6) and the first thread should get only odd numbers and the second thread only the even numbers)? I tried this, but the asserts aren't executing:
[Test]
public void Test()
{
var tickets = new Tickets(1, 4);
var t1 = new Thread(() =>
{
Assert.AreEqual(1, tickets.Dequeue());
Thread.Sleep(100);
Assert.AreEqual(3, tickets.Dequeue());
});
var t2 = new Thread(() =>
{
Assert.AreEqual(2, tickets.Dequeue());
Thread.Sleep(100);
Assert.AreEqual(4, tickets.Dequeue());
});
t1.Start();
t2.Start();
}
I would use chess: http://research.microsoft.com/en-us/projects/chess
CHESS is a tool for finding and reproducing Heisenbugs in concurrent programs. CHESS repeatedly runs a concurrent test ensuring that every run takes a different interleaving. If an interleaving results in an error, CHESS can reproduce the interleaving for improved debugging. CHESS is available for both managed and native programs.
The problem with multithreading and unit tests is one of timing. When you try to introduce multiple threads to unit tests you run the risk of non-reproducable test results, tests that pass sometimes but not other times.
But just to explain why your asserts may not be executing, the unit test completes before the threads. It needs to wait for the threads to complete rather than just kicking them off and moving on. It's also feasible that the unit test framework itself is not threadsafe or capable of Asserts being called from other threads.
Sorry it's not a solution, but I don't know of any automated testing solution for multithreaded code either.
See also: How should I unit test threaded code?