I have a logger which runs on it's own thread to prevent slowing down the main thread. Making it single-threaded would be easier, but I have a lot of slow code (writing to multiple files, getting info from stacktraces) and so on. The order of execution is:
Main thread
Logger.Log("foo"); //Creates stack trace for me
//Message and stack trace get added to queue
Logger thread (in while loop)
//Sees queued message
//Formats it (slow)
//Writes it to (one or more) streams and the console (*very* slow)
My problem is that if I make the logger thread a foreground thread, it prevents the app from closing once Main finishes, but if I make it background, it often gets cut off and doesn't manage to write most of the messages that were logged recently. Is there any way to make a function that will 'flush' the queue run just before the app quits, while keeping the thread background? (I can't always assume that people using my library will call a function before the app quits, and in certain cases (cough Unity cough) they really don't have much control)
You need some kind of synchronization between your threads. Instead of using your own Threads, consider using Tasks, these still run as Threads. From inside the main thread you can wait for the other tasks to finish or even signal them using a CancellationTokens.
When your "other logger thread" gets the Cancellation it can flush and exit it's log.
Here's a demo using Serilog with the Console Sink, you would probably want to use two different ILogger instances.
static async Task OtherLoggerAsync(CancellationToken ct)
{
await Task.Yield();
// This method is now running on it's own thread
while (true)
{
Log.Information("Other logger logged on thread");
await Task.Delay(750); // Mimic some work
if (ct.IsCancellationRequested)
{
Log.Logger.Information("OtherLoggerAsync() exiting");
break;
}
}
}
static async Task Main(string[] args)
{
Log.Logger = new LoggerConfiguration()
.WriteTo.Console()
.CreateLogger();
using (CancellationTokenSource cts = new CancellationTokenSource())
{
// Create the cancellation token
var ct = cts.Token;
// Start the other logger with the cancellation token
var t = OtherLoggerAsync(ct);
// Still in the main thread
for (var i = 0; i < 10; i++)
{
Log.Logger.Information("Main thread logged");
await Task.Delay(1000); // Mimic some work
}
// Main thread has finished. We want to stop the OtherLogger Thread
// if it has finsihed or not.
// signal the cancellation
cts.Cancel();
// wait for it to finish
Task.WaitAll(t);
Log.Logger.Information("Main thread exiting");
Log.CloseAndFlush();
}
}
Related
I've got a class with a static ConcurrentQueue. One class receives messages and puts them on the queue, whilst a different thread on this class reads them from that queue and processes them one at a time. That method is aborted with a cancellationtoken.
The method that empties the queue looks like this:
public async Task HandleEventsFromQueueAsync(CancellationToken ct, int pollDelay = 25)
{
while (true)
{
if (ct.IsCancellationRequested)
{
return;
}
if(messageQueue.TryDequeue(out ConsumeContext newMessage))
{
handler.Handle(newMessage);
}
try
{
await Task.Delay(pollDelay, ct).ConfigureAwait(true);
}
catch (TaskCanceledException)
{
return;
}
}
}
My testing methods look like this:
CancellationToken ct = source.Token;
Thread thread = new Thread(async () => await sut.HandleEventsFromQueueAsync(ct));
thread.Start();
EventListener.messageQueue.Enqueue(message1);
EventListener.messageQueue.Enqueue(message2);
await Task.Delay(1000);
source.Cancel(false);
mockedHandler.Verify(x => x.Handle(It.IsAny<ConsumeContext>()), Times.Exactly(2));
So I start my dequeueing method in its own thread, with a fresh cancellation token. Then I enqueue a couple of messages, give the process a second to handle them, and then use source.Cancel(false) to put an end to the thread and make the method return. Then I check that the handler was called the right number of times. Of course I'm testing this in a couple variations, with different message types and different times when I abort the dequeueing method.
The issue is that when I run any of my tests individually, they all succeed. But when I try to run them as a group, Visual Studio does not run every test. There's no error message, and the tests it does run succeed fine, but the run just stops after the second test.
I do not have an idea why this happens. My tests are all identical in structure. I'm aborting the dequeueing thread properly every time.
What could compel Visual Studio to stop a test run, without throwing any kind of error?
You are passing an async lambda to the Thread constructor. The Thread constructor doesn't understand async delegates (does not accept a Func<Task> argument), so you end up with an async void lambda. Async void methods should be avoided for anything that it's not an event handler. What happens in your case is that the explicitly created thread is terminated when the code hits the first await, and the rest of the body runs in ThreadPool threads. It seems that the code never fails with an exception, otherwise the process would crash (this is the default behavior of async void methods).
Suggestions:
Use a Task instead of a Thread. This way you'll have something to await before exiting the test.
CancellationToken ct = source.Token;
Task consumerTask = Task.Run(() => sut.HandleEventsFromQueueAsync(ct));
EventListener.messageQueue.Enqueue(message1);
EventListener.messageQueue.Enqueue(message2);
await Task.Delay(1000);
source.Cancel(false);
await consumerTask; // Wait the task to complete
mockedHandler.Verify(x => x.Handle(It.IsAny<ConsumeContext>()), Times.Exactly(2));
Consider using a BlockingCollection or an asynchronous queue like a Channel instead of a ConcurrentQueue. Polling is an awkward and inefficient technique. With a blocking or async queue you'll not be obliged to do loops waiting for new messages to arrive. You'll be able to enter a waiting state, and notified instantly when a new message arrives.
Configure the awaiting with ConfigureAwait(false). ConfigureAwait(true) is the default and does nothing.
Consider propagating cancellation by throwing an OperationCanceledException. This is the standard way of propagating cancellation in .NET. So instead of:
if (ct.IsCancellationRequested) return;
...it is preferable to do this:
ct.ThrowIfCancellationRequested();
I have solved my own issue. Turns out that the newly created thread threw an exception, and when threads throw exceptions those are ignored, but they still stop the unit test from happening. After fixing the issue causing the exception, the tests work fine.
I am using Task to create and perform some operations by a different thread, once the operation is done I also have called back to be called.
System.Threading.Tasks.Task.Factory.StartNew(() =>
this._httpService.CreateRecord(new Uri(Configuration.Current.CreateRecordUrl), httpObj)).ContinueWith(
(response) =>
{
if (!response.IsFaulted)
{
if (httpObj.CallBack != null)
{
httpObj.CallBack(response.Result);
}
}
else {
this._logger.Error("There was some error which causes the task to fail");
}
});
My console application's main thread is not waiting for the Task thread to complete, because it's background thread.
How can I make task thread foreground thread?
Thanks
StartNew() method returns a Task instance. Calling Wait() method on the returned task will block the main thread until the task finishes.
static void Main(string[] args)
{
var task = Task.Factory.StartNew(() =>
{
// ...
});
task.Wait(); // The main application thread waits here until the task returns
}
My console application's main thread is not waiting for the Task thread to complete, because it's background thread.
Your application is not waiting for the task, because you don't tell it to do so.
As others have already stated, use Wait/Result or await to wait for the task, depending on whether you're in an asynchronous context or not.
How can i make task thread foreground thread.
Most likely you don't want to do that in the first place. A background thread is a thread that terminates when all foreground threads have ended. Thread pool threads are inherently background threads, if you actually want to schedule your task to a foreground thread, that is, a thread that will keep the app process alive even if the main thread is finished, you'll have to create your own TaskScheduler. That, btw, would be a reason to use Task.Factory.StartNew. If you don't need Task.Factory.StartNew, go for Task.Run.
You should wait for completion of the Task in your main thread.
Change your code to
var task = System.Threading.Tasks.Task.Factory.StartNew(() =>
this._httpService.CreateRecord(new Uri(Configuration.Current.CreateRecordUrl), httpObj)).ContinueWith(
(response) =>
{
if (!response.IsFaulted)
{
if (httpObj.CallBack != null)
{
httpObj.CallBack(response.Result);
}
}
else {
this._logger.Error("There was some error which causes the task to field");
}
});
task.Wait(); // Wait till your Task has finished.
The Wait() method has some overloads to specify how long to wait. Also you have to add some exception handling if Task execution fails due to an exception of cancellation.
Try creating a fresh new Thread instead of taking from the pool. For eg:
Thread t = new Thread(()=>
{
//all your code goes here
});
t.IsBackground = false; //by default it will be foreground. so don't need this line in your case
t.Start();
This will create a foreground thread for u and it will make sure the thread completes its execution.
I have an application which should finish within 30 minutes. The components of the application are run using threadpool.
So
//queue first all the components
//when the Collect method for each of the components finishes it will set the event
ManualResetEvent serverEvent = new ManualResetEvent(false);
sectionsCompleted.Add(serverEvent);
ThreadPool.QueueUserWorkItem(serverInfo.Collect,"ServerInfo ");
ManualResetEvent cpuEvent= new ManualResetEvent(false);
sectionsCompleted.Add(cpuEvent);
ThreadPool.QueueUserWorkItem(cpuInfo.Collect,"CPUInfo ");
//then wait for all the components to finish
WaitHandle.WaitAll(sectionsCompleted.ToArray());
So the logic is to call all the components in ThreadPool and use ManualResetEvent class to signal the main thread that the component has finished.
Now i want to use the ElapsedEvent Handler to make sure that the code finishes gracefully in some time frame(say 30 minutes). So after 30 minutes if there are still some threads running i want to abort them.
So my question will ElapsedEventHandler delegate be called at all? or will the main thread wait for WaitHandle.WaitAll(sectionsCompleted.ToArray()) ?
Is there any other way i can achieve this functionality of stopping all threads in a thread pool after some time interval.
If you setup the timer, the event handler for the timer, and start the timer before the above code (or at least before the WaitAll) then
your timer's Elapsed event will fire,
your Main thread will wait at the WaitAll
but you could just as easily do something like:
if (!WaitHandle.WaitAll(sectionsCompleted.ToArray(), TimeSpan.FromMinutes(30)))
{
// did not finish in the 30 minute timespan, so kill the threads
}
If you do the above you won't have to worry about synchronising your event handler for the timer (which may try and kill a thread just as it completes) and the Main method which is waiting on the WaitHandles (and may therefore complete while the event handler thinks the thread is being killed).
If you are able (.NET version depending) then Tasks would be very well suited to this as you could use a CancellationToken to allow you to kill each task gracefully if it has not completed. See MSDN: Task Cancellation for something like the below. If you can't use Task you can just wire this same solution up yourself. One possible technique is to use more WaitHandles (also see below).
This approach will also let you move the Wait+Cancel code into a separate thread. You can therefore release your UI or main code thread immediately the worker threads are created. This has the added advantage that you can also signal from the control thread to the single instance of the Wait+Cancel code to trigger a premature cancellation.
// use the same CancellationTokenSource to create all tasks
var tokenSource2 = new CancellationTokenSource();
// for each task, use the following structure
CancellationToken ct = tokenSource2.Token;
var task = Task.Factory.StartNew(() =>
{
// Were we already canceled?
ct.ThrowIfCancellationRequested();
bool moreToDo = true;
// make sure any loops and other methods check the ct.IsCancellationRequested regularly
while (moreToDo)
{
if (ct.IsCancellationRequested)
{
// Clean up any resources, transactions etc. here, then...
ct.ThrowIfCancellationRequested();
}
}
}, tokenSource2.Token); // Pass same token to StartNew.
// add each task to the tasks list
tasks.Add(task);
// once all tasks created, wait on them and cancel if they overrun
// by passing the token, another thread could even cancel the whole operation ahead of time
if (!Task.WaitAll(tasks.ToArray(), (int)TimeSpan.FromMinutes(30).TotalMilliseconds,
tokenSource2.Token))
{
// did not finish in the 30 minute timespan, so kill the threads
tokenSource2.Cancel();
try
{
// Now wait for the tasks to cancel
Task.WaitAll(tasks.ToArray());
}
catch (AggregateException ae)
{
// handle any unexpected task exceptions here
}
}
Or in .NET 2.0 without Tasks:
// in Main thread ...
ManualResetEvent serverEventCancelled = new ManualResetEvent(false);
cancellationMres.Add(serverEventCancelled);
// Inside the thread, do this regularly - zero timeout returns instantly ...
if (serverEventCancelled.WaitOne(0))
{
// do cancellation and ...
// now set the "completed" waithandle (or do something similar to let Main know we are done)
serverEvent.Set();
return;
}
// In Main thread ...
if (!WaitHandle.WaitAll(sectionsCompleted.ToArray(), TimeSpan.FromMinutes(30)))
{
foreach (var cancellationMre in cancellationMres)
{
cancellationMre.Set();
}
WaitHandle.WaitAll(sectionsCompleted.ToArray());
}
ElapsedEventHandler delegate be called at all?
yes
will the main thread wait for WaitHandle.WaitAll(sectionsCompleted.ToArray()) ?
yes
but you need to signal the eventhandler in your thread(like cpuInfo.Collect) ,
in .net 4.5, you also can use CancellationTokenSource(TimeSpan) to cancel the thread after period time.
btw: you should put WaitHandle.WaitAll(sectionsCompleted.ToArray()) in non-ui thread, or it will block your UI.
I created ten threads who will request the server separately. Now, Each thread is requesting the server successfully but no thread is getting the response.
If the thread is not in active state (due to Operating System Process Scheduling), who will receive the response?
private static void ThreadFunc()
{
var response = CallServer();
Console.writeline(response.Message);
}
Following line of code never hit.
Console.writeline(response.Message);
When waiting for a response, your thread will never be active. It is waiting after all.
The OS marks the underlying IO as completed and marks the thread as ready. It will be scheduled some time in the future to process the results of the completed IO.
What does "active" even mean? For the purposes of this discussion, threads can be blocked, ready and running. During a wait or IO, a thread is blocked. When that wait completes, it is marked ready. It starts to run at some point in time later when the OS decides to schedule it.
A foreground/application thread must stay alive for background threads to completed. If, in your code, you're using ThreadPool threads (which Tasks use by default), and your console application's main thread completes without waiting for these background threads to completed, the process terminates.
Here's an example using Tasks:
static void Main()
{
List<Task> tasks = new List<Task>();
for( int i = 0; i < 10; ++i )
{
tasks.Add( Task.Factory.StartNew( () => ThreadFunc() ) );
}
// need this to keep process alive
// will continue once all tasks complete
Task.WaitAll( tasks.ToArray() );
}
I am writing a library that is consuming a resource and for whatever reason the API was designed in a way that events will be raised on different threads but calls of the API has to be done on the main thread.
Let's say the API that I am trying to consume is defined as (I am going to omit event definitions):
public sealed class DodgyService
{
public void MethodThatHasToBeCalledOnTheMainThread() { ... }
}
To consume this API I have added a service on my library called Service (Yup, very original name) that will create a new task (that will run on the main thread as I am specifying a TaskScheduler that has been created from the SynchronizationContext).
Here is my implementation:
public class Service
{
private readonly TaskFactory _taskFactory;
private readonly TaskScheduler _mainThreadScheduler;
public Service(TaskFactory taskFactory, TaskScheduler mainThreadScheduler)
{
_taskFactory = taskFactory;
_mainThreadScheduler = mainThreadScheduler;
}
// Assume this method can be called from any thread.
// In this sample is called by the main thread but most of the time
// the caller will be running on a background thread.
public Task ExecuteAsync(string taskName)
{
return _taskFactory.StartNew(
() => ReallyLongCallThatForWhateverStupidReasonHasToBeCalledOnMainThread(taskName),
new CancellationToken(false), TaskCreationOptions.None, _mainThreadScheduler)
.ContinueWith(task => Trace.TraceInformation("ExecuteAsync has completed on \"{0}\"...", taskName));
}
private void ReallyLongCallThatForWhateverStupidReasonHasToBeCalledOnMainThread(string taskName)
{
Trace.TraceInformation("Starting \"{0}\" really long call...", taskName);
new DodgyService().MethodThatHasToBeCalledOnTheMainThread();
Trace.TraceInformation("Finished \"{0}\" really long call...", taskName);
}
}
Now, if I perform the call of my service (on the main thread) and try to wait on the main thread the application enters a deadlock as the main thread will be waiting for the tasks that has been scheduled to execute on the main thread.
How do I marshall these calls onto the main thread without blocking the entire process?
At some point I thought on performing the detection of the main thread before creating the new task but I don't want to hack this.
For anybody interested, I got a gist here with the code and a WPF app that exhibits the issue.
On btw, the library has to be written on .net framework 4.0
Edit!
I solved my issue following the advice provided by Scott Chamberlain as provided here
as the main thread will be waiting for the tasks
That's a guaranteed deadlock. A task cannot execute on the main thread until it is idle, running the dispatcher loop (aka pumping the message loop). It is that dispatcher loop that implements the magic of getting code to run on a specific thread. The main thread however won't be idle, it is "waiting for the tasks". So the task cannot complete because the main thread won't go idle, the main thread cannot go idle because the task won't complete. Deadlock city.
You must rewrite the code so your main thread won't wait. Move whatever code that appears after the wait call to another task that runs on the main thread, just like that ReallyLongCall().
Do note that you don't seem to get any mileage at all from using tasks, your snippet suggests that none of the code that matters runs on a worker thread. So you might as well call it directly, solves the problem as well.
From your example program:
private void HandleClosed(object sender, EventArgs e)
{
var list = new[]
{
_service.ExecuteAsync("first task"),
_service.ExecuteAsync("second task"),
_service.ExecuteAsync("third task")
};
//uncommenting this line blocks all three previous activities as expected
//as it drives the current main thread to wait for other tasks waiting to be executed by the main thread.
//Task.WaitAll(list);
}
Task.WaitAll is a blocking call, you can't perform blocking calls on the main thread or you will cause deadlocks. What you can do (if you are using Visual Studio 2012 or newer) is use the NuGet package Microsoft.Bcl.Async which gives async/await support to .Net 4.0.
After adding the package change the code to
private async void HandleClosed(object sender, EventArgs e)
{
var list = new[]
{
_service.ExecuteAsync("first task"),
_service.ExecuteAsync("second task"),
_service.ExecuteAsync("third task")
};
//uncommenting this line blocks all three previous activities as expected
//as it drives the current main thread to wait for other tasks waiting to be executed by the main thread.
await TaskEx.WhenAll(list);
}
and your program will no-longer deadlock (it also does not execute any code after await TaskEx.WhenAll(list); but that is because this code is running during the shutdown process and when you await it lets the shutdown continue on processing, if it was placed elsewhere like a click event you would see more normal behavior).
Another option is have a 2nd "Main Thread" and dispatch the work to that. Often when something must be run on "the main" thread are actually saying they require to be run on "a STA Windows Message pumped that the object was initially created on" thread. Here is a example how to to it (taken from here)
private void runBrowserThread(Uri url) {
var th = new Thread(() => {
var br = new WebBrowser();
br.DocumentCompleted += browser_DocumentCompleted;
br.Navigate(url);
Application.Run();
});
th.SetApartmentState(ApartmentState.STA);
th.Start();
}
void browser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e) {
var br = sender as WebBrowser;
if (br.Url == e.Url) {
Console.WriteLine("Natigated to {0}", e.Url);
Application.ExitThread(); // Stops the thread
}
}
#HansPassant is correct; by blocking the dispatcher thread to wait on the tasks, you prevent the tasks from ever being executed. The simplest change you could probably make would be to replace Task.WaitAll(list) with:
_taskFactory.ContinueWhenAll(
list,
tasks => { /* resume here */ });
...and then move any code which followed the call to WaitAll() into the continuation. Remember to check the task results and respond appropriately to any exceptions that might have occurred.
But unless there is some tangible benefit to using Tasks that is not apparent in your example code, I would heed Hans' advice and simply forego the Tasks in favor of synchronous calls.