I have a simple windows service written, here is its skeleton:
internal class ServiceModel {
private Thread workerThread;
private AutoResetEvent finishedEvent;
private Int32 timeout = 60000*15;
public void Start() {
this.workerThread = new Thread(this.Process);
this.finishedEvent = new AutoResetEvent(false);
this.workerThread.Start();
}
public void Stop() {
this.finishedEvent.Set();
this.workerThread.Join(30000);
}
public void Process() {
while(!this.finishedEvent.WaitOne(timeout)) {
// run things here
}
}
}
the first thing
The first thing that I can't understand is that service waits one timeout before running. Would rewriting the new AutoResetEvent(false); to new AutoResetEvent(true); cause a service to start without waiting?
the second thing
Due to some internal reasons (requesting data from external server/service, exception handling) sometimes it is not enough to wait that fixed 15..30-minutes timeout.
How do I rewrite it to work without a fixed timeout?
Do I need to remove that AutoResetEvent instance at all and run Process body inside an infinite loop?
public void Process() {
while(true) {
// run things here
}
}
edit. try-catch/lock
In Process method there is a global try-catch block:
public void Process() {
do {
try {
// processing goes here
}
catch(Exception ex) {
Logger.Log.Warn(ex); // or Log.Fatal(ex)...
}
}
while(true);
}
if I use a synchronization object where do I put the lock statement so that I'm able to call break when isStopped is true?
You don't have to deal with low-level thread and synchronization primitives API. Consider using Task Parallel Library (TPL). It's easy to implement OnStop using TPL cancellation framework:
using System.ServiceProcess;
using System.Threading;
using System.Threading.Tasks;
namespace WindowsService1
{
public partial class Service1 : ServiceBase
{
CancellationTokenSource _mainCts;
Task _mainTask;
public Service1()
{
InitializeComponent();
}
async Task MainTaskAsync(CancellationToken token)
{
while (true)
{
token.ThrowIfCancellationRequested();
// ...
await DoPollingAsync(token);
// ...
}
}
protected override void OnStart(string[] args)
{
_mainCts = new CancellationTokenSource();
_mainTask = MainTaskAsync(_mainCts.Token);
}
protected override void OnStop()
{
_mainCts.Cancel();
try
{
_mainTask.Wait();
}
catch
{
if (!_mainTask.IsCanceled)
throw;
}
}
}
}
Inside MainTaskAsync you can use Task.Run for any CPU-bound work items.
using Threads you can achieve your requirement using the following code:
internal class ServiceModel {
private Thread workerThread;
private object syncLock = new object();
private bool stop = false;
public void Start() {
this.workerThread = new Thread(this.Process);
this.workerThread.Start();
}
public void Stop() {
lock(syncLock) stop = true;
this.workerThread.Join(30000);
}
public void Process() {
while(true){
//your stuff here.
lock(syncLock)
{
if(stop)
break;
}
Thread.Sleep(30000);
}
}
}
Related
In a small project i am working on i have the neccessity for a component to execute a components shutdown code in the same thread that it was initialized in. However unlike in WPF/Winforms/Web the synchronizationcontext which takes care of this does not work.
My guess is that the lack of a synchronization context is the issue that causes the lack of utilization for ConfigureAwait(true).
Does someone know how to properly implement this?
I read this article but could not make any sense of it yet. Perhaps it was too late yesterday.
Minimal Repro:
using System;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleSyncContext
{
class Program
{
static async Task Main(string[] args)
{
Console.WriteLine($"Thread: {Thread.CurrentThread.ManagedThreadId}");
await SomeBackgroundWorkAsync();
// if this is the same thread as above the question is solved.
Console.WriteLine($"Thread: {Thread.CurrentThread.ManagedThreadId}");
}
private static async Task SomeBackgroundWorkAsync()
{
await Task.Run(() => { });
}
}
}
As you already figured out, console application by default doesn't have synchronization context, so ConfigureAwait has no effect, and continuation after your await SomePageLoad() will run on random thread pool thread. Note that using async main method is essentially equivalent to this:
static async Task AsyncMain() { ... } // your `async Task Main method`
// real Main method generated by compiler
static void RealMain() {
AsyncMain().GetAwaiter().GetResult();
}
In your case you don't need any synchronization context though. What you want is initialize CefSharp on main thread and shutdown CefSharp on main thread. So instead of using async Main - you can do the same as above, but initialize and shutdown Cef outside of async method:
static void Main(string[] args) {
// starting with thread 1
Cef.Initialize(new CefSettings());
try {
AsyncMain(args).GetAwaiter().GetResult();
}
finally {
// we are on main thread here
Cef.Shutdown();
}
}
static async Task AsyncMain(string[] args) {
await SomePageLoad(); // more stuff here
}
Edit: if you insist on using synchronization context then it can be done, but will add a lot of complications for nothing. Out goal is create synchronization context which will run all actions on the same thread. This case be done with simple actions queue, here is basic implementation (don't use it in production, provided as an example only, no exception handling and so on):
class CustomSyncContext : SynchronizationContext {
private readonly BlockingCollection<WorkItem> _queue = new BlockingCollection<WorkItem>(new ConcurrentQueue<WorkItem>());
private readonly Thread _thread;
public CustomSyncContext() {
// start new thread which will handle all callbacks
_thread = new Thread(() => {
// set outselves as current sync context for this thread
SynchronizationContext.SetSynchronizationContext(this);
foreach (var item in _queue.GetConsumingEnumerable()) {
try {
// execute action
item.Action();
}
finally {
// if this action is synchronous, signal the caller
item.Signal?.Set();
}
}
});
_thread.Start();
}
public override void Post(SendOrPostCallback d, object state) {
// Post means acion is asynchronous, just queue and forget
_queue.Add(new WorkItem(() => d(state), null));
}
public override void Send(SendOrPostCallback d, object state) {
// Send means action is synchronous, wait on a single until our thread executes it
using (var signal = new ManualResetEvent(false)) {
_queue.Add(new WorkItem(() => d(state), signal));
signal.WaitOne();
}
}
public void Shutdown() {
// signal thread that no more callbacks are expected
_queue.CompleteAdding();
}
public void WaitForShutdown() {
_thread.Join();
}
private class WorkItem {
public WorkItem(Action action, ManualResetEvent signal) {
Action = action;
Signal = signal;
}
public Action Action { get; }
public ManualResetEvent Signal { get; }
}
}
And your code then becomes:
var ctx = new CustomSyncContext();
ctx.Send(async (_) => {
try {
// starting with thread 1
Cef.Initialize(new CefSettings());
// this method returns on thread 4
await SomePageLoad();
}
finally {
Cef.Shutdown();
// signal the context we are done, so that main thread can unblock
ctx.Shutdown();
Console.WriteLine("done");
}
}, null);
ctx.WaitForShutdown();
Now your code runs on custom synchronization context, and continuation after await SomePageLoad(); will be posted to that synchronization context and executed by our thread (the same thread which inited CefSharp) (no ConfigureAwait(true) is needed, as it's already true by default). Note that we achieved nothing useful - we have one more thread, and our main thread is still blocked waiting for the whole operation to complete (there is no sensible way around that).
Edit 2: here is variation which does not require separate thread, but is not much better:
class CustomSyncContext : SynchronizationContext {
private readonly BlockingCollection<WorkItem> _queue = new BlockingCollection<WorkItem>(new ConcurrentQueue<WorkItem>());
public override void Post(SendOrPostCallback d, object state) {
// Post means acion is asynchronous, just queue and forget
_queue.Add(new WorkItem(() => d(state), null));
}
public override void Send(SendOrPostCallback d, object state) {
// Send means action is synchronous, wait on a single until our thread executes it
using (var signal = new ManualResetEvent(false)) {
_queue.Add(new WorkItem(() => d(state), signal));
signal.WaitOne();
}
}
public void Shutdown() {
// signal thread that no more callbacks are expected
_queue.CompleteAdding();
}
public void Start() {
// now we run the loop on main thread
foreach (var item in _queue.GetConsumingEnumerable()) {
try {
// execute action
item.Action();
}
finally {
// if this action is synchronous, signal the caller
item.Signal?.Set();
}
}
}
private class WorkItem {
public WorkItem(Action action, ManualResetEvent signal) {
Action = action;
Signal = signal;
}
public Action Action { get; }
public ManualResetEvent Signal { get; }
}
}
static async Task Main(string[] args) {
var ctx = new CustomSyncContext();
// set sync context
SynchronizationContext.SetSynchronizationContext(ctx);
// now execute our async stuff
var task = DoStuff().ContinueWith(x => ctx.Shutdown());
// now run the loop of sync context on the main thread.
// but, how do we know when to stop? Something from outside should singal that
// in the case signal is completion of DoStuff task
// note that most of the time main thread is still blocked while waiting for items in queue
ctx.Start();
}
private static async Task DoStuff() {
try {
// starting with thread 1
Cef.Initialize(new CefSettings());
// this method returns on thread 4
await SomePageLoad();
}
finally {
Cef.Shutdown();
// signal the context we are done, so that main thread can unblock
Console.WriteLine("done");
}
}
Your problem is indeed the lack of a Synchronisation context. You can't use ConfigureAwait(true) as this implies that you need to return to the original scheduler/context which does not exist.
Custom implementation
A very simple implementation that ought to do the trick is the one found here. Basically two steps.
Implement a custom synchronization context
public class CustomSynchronizationContext : SynchronizationContext
{
public override void Post(SendOrPostCallback action, object state)
{
SendOrPostCallback actionWrap = (object state2) =>
{
SynchronizationContext.SetSynchronizationContext(new CustomSynchronizationContext());
action.Invoke(state2);
};
var callback = new WaitCallback(actionWrap.Invoke);
ThreadPool.QueueUserWorkItem(callback, state);
}
public override SynchronizationContext CreateCopy()
{
return new CustomSynchronizationContext();
}
public override void Send(SendOrPostCallback d, object state)
{
base.Send(d, state);
}
public override void OperationStarted()
{
base.OperationStarted();
}
public override void OperationCompleted()
{
base.OperationCompleted();
}
}
Initaliaze it and use it
static void Main()
{
var context = new CustomSynchronizationContext();
SynchronizationContext.SetSynchronizationContext(context);
AsyncEx library
You can also use the AsyncEx library
private static void Main(string[] args)
{
AsyncContext.Run(() => AsyncMethod(args));
}
static async void AsyncMethod(string[] args)
{
await something().ConfigureAwait(true);
}
I've been building out a service that processes files using a Queue<string> object to manage the items.
public partial class BasicQueueService : ServiceBase
{
private readonly EventWaitHandle completeHandle =
new EventWaitHandle(false, EventResetMode.ManualReset, "ThreadCompleters");
public BasicQueueService()
{
QueueManager = new Queue<string>();
}
public bool Stopping { get; set; }
private Queue<string> QueueManager { get; }
protected override void OnStart(string[] args)
{
Stopping = false;
ProcessFiles();
}
protected override void OnStop()
{
Stopping = true;
}
private void ProcessFiles()
{
while (!Stopping)
{
var count = QueueManager.Count;
for (var i = 0; i < count; i++)
{
//Check the Stopping Variable again.
if (Stopping) break;
var fileName = QueueManager.Dequeue();
if (string.IsNullOrWhiteSpace(fileName) || !File.Exists(fileName))
continue;
Console.WriteLine($"Processing {fileName}");
Task.Run(() =>
{
DoWork(fileName);
})
.ContinueWith(ThreadComplete);
}
if (Stopping) continue;
Console.WriteLine("Waiting for thread to finish, or 1 minute.");
completeHandle.WaitOne(new TimeSpan(0, 0, 15));
completeHandle.Reset();
}
}
partial void DoWork(string fileName);
private void ThreadComplete(Task task)
{
completeHandle.Set();
}
public void AddToQueue(string file)
{
//Called by FileWatcher/Manual classes, not included for brevity.
lock (QueueManager)
{
if (QueueManager.Contains(file)) return;
QueueManager.Enqueue(file);
}
}
}
Whilst researching how to limit the number of threads on this (I've tried a manual class with an incrementing int, but there's an issue where it doesn't decrement properly in my code), I came across TPL DataFlow, which seems like its a better fit for what I'm trying to achieve - specifically, it allows me to let the framework handle threading/queueing, etc.
This is now my service:
public partial class BasicDataFlowService : ServiceBase
{
private readonly ActionBlock<string> workerBlock;
public BasicDataFlowService()
{
workerBlock = new ActionBlock<string>(file => DoWork(file), new ExecutionDataflowBlockOptions()
{
MaxDegreeOfParallelism = 32
});
}
public bool Stopping { get; set; }
protected override void OnStart(string[] args)
{
Stopping = false;
}
protected override void OnStop()
{
Stopping = true;
}
partial void DoWork(string fileName);
private void AddToDataFlow(string file)
{
workerBlock.Post(file);
}
}
This works well. However, I want to ensure that a file is only ever added to the TPL DataFlow once. With the Queue, I can check that using .Contains(). Is there a mechanism that I can use for TPL DataFlow?
Your solution with Queue works only if file goes into your service twice in a small period of time. If it came again in, say, few hours, queue will not contain it, as you Dequeue it from there.
If this solution is expected, then you may use a MemoryCache to store file paths being already handled, like this:
using System.Runtime.Caching;
private static object _lock = new object();
private void AddToDataFlow(string file)
{
lock (_lock)
{
if (MemoryCache.Default.Contains(file))
{
return;
}
// no matter what to put into the cache
MemoryCache.Default[file] = true;
// we can now exit the lock
}
workerBlock.Post(file);
}
However, if your application must run for a long time (which service is intended to do), you'll eventually run out of memory. In that case you probably need to store your file paths in database or something, so even after restarting the service your code will restore the state.
You can check it inside of DoWork.
You have to save in Hash already works items and check current filename doesn't exist in hash.
When using the StartNew() method to kick off a process on a new thread, I need to figure out how to make another call into this object in that same thread (I assume this would be some sort of Join operation?).
The following example is dumbed down to illustrate the meat of what I am trying to do. I am well aware it is severely lacking in basic concurrency considerations. But I didn't want to cloud the code with all of that logic, so please forgive me on that.
The following console app shows what I am trying to accomplish. Assume on the StartNew() call a new thread with ID 9976 is created and the method invoked there. I would like the subsequent call to ProcessImmediate() in the file system watcher change event handler to be made on thread 9976 as well. As it stands, the call would share the same thread that is used for the file system watcher change event.
Can this be done, and if so, how?
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
var runner = new Runner();
runner.Run();
Console.ReadKey();
}
}
public class Runner
{
private Activity _activity = null;
private FileSystemWatcher _fileSystemWatcher;
public void Run()
{
_activity = new Activity();
// start activity on a new thread
Task.Factory.StartNew(() => _activity.Go());
_fileSystemWatcher = new FileSystemWatcher();
_fileSystemWatcher.Filter = "*.watcher";
_fileSystemWatcher.Path = "c:\temp";
_fileSystemWatcher.Changed += FileSystemWatcher_Changed;
_fileSystemWatcher.EnableRaisingEvents = true;
}
private void FileSystemWatcher_Changed(object sender, FileSystemEventArgs e)
{
// WANT TO CALL THIS FOR ACTIVITY RUNNING ON PREVIOUSLY CALLED THREAD
_activity.ProcessImmediate();
}
}
public class Activity
{
public void Go()
{
while (!Stop)
{
// for purposes of this example, magically assume that ProcessImmediate has not been called when this is called
DoSomethingInteresting();
System.Threading.Thread.Sleep(2000);
}
}
protected virtual void DoSomethingInteresting() { }
public void ProcessImmediate()
{
// for purposes of this example, assume that Go is magically in its sleep state when ProcessImmediate is called
DoSomethingInteresting();
}
public bool Stop { get; set; }
}
}
* UPDATE *
Thanks for the excellent responses. I took Mike's suggestion and implemented it for my console app. Below is the full working code which also includes the use of a cancellation token. I post this in case someone else might find it useful.
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
var runner = new Runner();
runner.Run();
Console.ReadKey();
runner.Stop();
Console.ReadKey();
}
}
public class Runner
{
private Activity _activity = null;
private FileSystemWatcher _fileSystemWatcher;
private CancellationTokenSource _cts = new CancellationTokenSource();
public void Stop() { _cts.Cancel(); }
public void Run()
{
_activity = new Activity();
// start activity on a new thread
var task = new Task(() => _activity.Go(_cts.Token), _cts.Token, TaskCreationOptions.LongRunning);
task.Start();
_fileSystemWatcher = new FileSystemWatcher();
_fileSystemWatcher.Filter = "*.watcher";
_fileSystemWatcher.Path = "C:\\Temp\\FileSystemWatcherPath";
_fileSystemWatcher.Changed += FileSystemWatcher_Changed;
_fileSystemWatcher.EnableRaisingEvents = true;
}
private void FileSystemWatcher_Changed(object sender, FileSystemEventArgs e)
{
// WANT TO CALL THIS FOR ACTIVITY RUNNING ON PREVIOUSLY CALLED THREAD
_activity.ProcessImmediate();
}
}
public class Activity : IDisposable
{
private AutoResetEvent _processing = new AutoResetEvent(false);
public void Go(CancellationToken ct)
{
Thread.CurrentThread.Name = "Go";
while (!ct.IsCancellationRequested)
{
// for purposes of this example, magically assume that ProcessImmediate has not been called when this is called
DoSomethingInteresting();
_processing.WaitOne(5000);
}
Console.WriteLine("Exiting");
}
protected virtual void DoSomethingInteresting()
{
Console.WriteLine(string.Format("Doing Something Interesting on thread {0}", Thread.CurrentThread.ManagedThreadId));
}
public void ProcessImmediate()
{
// for purposes of this example, assume that Go is magically in its sleep state when ProcessImmediate is called
_processing.Set();
}
public void Dispose()
{
if (_processing != null)
{
_processing.Dispose();
_processing = null;
}
}
}
}
First, you should use TaskCreationOptions.LongRunning if you are creating a task that will not complete quickly. Second, use an AutoResetEvent to signal the waiting thread to wake up. Note that below ProcessImmediate will return before DoSomethingInteresting has completed running on the other thread. Example:
using System.Threading;
public class Activity : IDisposable
{
private AutoResetEvent _processing = new AutoResetEvent(false);
public void Go()
{
while (!Stop)
{
// for purposes of this example, magically assume that ProcessImmediate has not been called when this is called
DoSomethingInteresting();
_processing.WaitOne(2000);
}
}
protected virtual void DoSomethingInteresting() { }
public void ProcessImmediate()
{
_processing.Set();
}
public bool Stop { get; set; }
public void Dispose()
{
if (_processing != null)
{
_processing.Dispose();
_processing = null;
}
}
}
User mike has given a better solution, which will be appropriate when you like to call the same method immediately. If you want to call a different methods immediately I'll expand mike's answer to achieve that.
using System.Threading;
public class Activity : IDisposable
{
private AutoResetEvent _processing = new AutoResetEvent(false);
private ConcurrentQueue<Action> actionsToProcess = new ConcurrentQueue<Action>();
public void Go()
{
while (!Stop)
{
// for purposes of this example, magically assume that ProcessImmediate has not been called when this is called
DoSomethingInteresting();
_processing.WaitOne(2000);
while(!actionsToProcess.IsEmpty)
{
Action action;
if(actionsToProcess.TryDeque(out action))
action();
}
}
}
protected virtual void DoSomethingInteresting() { }
public void ProcessImmediate(Action action)
{
actionsToProcess.Enqueue(action);
_processing.Set();
}
public bool Stop { get; set; }
public void Dispose()
{
if (_processing != null)
{
_processing.Dispose();
_processing = null;
}
}
}
To execute different methods on the same thread you can use a message loop that dispatches incoming requests. A simple option would be to use the event loop scheduler of the Reactive Extensions and to "recursively" schedule your Go() function - if in the mean time a different operation is scheduled it would be processed before the next Go() operation.
Here is a sample:
class Loop
: IDisposable
{
IScheduler scheduler = new EventLoopScheduler();
MultipleAssignmentDisposable stopper = new MultipleAssignmentDisposable();
public Loop()
{
Next();
}
void Next()
{
if (!stopper.IsDisposed)
stopper.Disposable = scheduler.Schedule(Handler);
}
void Handler()
{
Thread.Sleep(1000);
Console.WriteLine("Handler: {0}", Thread.CurrentThread.ManagedThreadId);
Next();
}
public void Notify()
{
scheduler.Schedule(() =>
{
Console.WriteLine("Notify: {0}", Thread.CurrentThread.ManagedThreadId);
});
}
public void Dispose()
{
stopper.Dispose();
}
}
static void Main(string[] args)
{
using (var l = new Loop())
{
Console.WriteLine("Press 'q' to quit.");
while (Console.ReadKey().Key != ConsoleKey.Q)
l.Notify();
}
}
I'm having a small background thread which runs for the applications lifetime - however when the application is shutdown, the thread should exit gracefully.
The problem is that the thread runs some code at an interval of 15 minutes - which means it sleeps ALOT.
Now in order to get it out of sleep, I toss an interrupt at it - my question is however, if there's a better approach to this, since interrupts generate ThreadInterruptedException.
Here's the gist of my code (somewhat pseudo):
public class BackgroundUpdater : IDisposable
{
private Thread myThread;
private const int intervalTime = 900000; // 15 minutes
public void Dispose()
{
myThread.Interrupt();
}
public void Start()
{
myThread = new Thread(ThreadedWork);
myThread.IsBackground = true; // To ensure against app waiting for thread to exit
myThread.Priority = ThreadPriority.BelowNormal;
myThread.Start();
}
private void ThreadedWork()
{
try
{
while (true)
{
Thread.Sleep(900000); // 15 minutes
DoWork();
}
}
catch (ThreadInterruptedException)
{
}
}
}
There's absolutely a better way - either use Monitor.Wait/Pulse instead of Sleep/Interrupt, or use an Auto/ManualResetEvent. (You'd probably want a ManualResetEvent in this case.)
Personally I'm a Wait/Pulse fan, probably due to it being like Java's wait()/notify() mechanism. However, there are definitely times where reset events are more useful.
Your code would look something like this:
private readonly object padlock = new object();
private volatile bool stopping = false;
public void Stop() // Could make this Dispose if you want
{
stopping = true;
lock (padlock)
{
Monitor.Pulse(padlock);
}
}
private void ThreadedWork()
{
while (!stopping)
{
DoWork();
lock (padlock)
{
Monitor.Wait(padlock, TimeSpan.FromMinutes(15));
}
}
}
For more details, see my threading tutorial, in particular the pages on deadlocks, waiting and pulsing, the page on wait handles. Joe Albahari also has a tutorial which covers the same topics and compares them.
I haven't looked in detail yet, but I wouldn't be surprised if Parallel Extensions also had some functionality to make this easier.
You could use an Event to Check if the Process should end like this:
var eventX = new AutoResetEvent(false);
while (true)
{
if(eventX.WaitOne(900000, false))
{
break;
}
DoWork();
}
There is CancellationTokenSource class in .NET 4 and later which simplifies this task a bit.
private readonly CancellationTokenSource cancellationTokenSource =
new CancellationTokenSource();
private void Run()
{
while (!cancellationTokenSource.IsCancellationRequested)
{
DoWork();
cancellationTokenSource.Token.WaitHandle.WaitOne(
TimeSpan.FromMinutes(15));
}
}
public void Stop()
{
cancellationTokenSource.Cancel();
}
Don't forget that CancellationTokenSource is disposable, so make sure you dispose it properly.
One method might be to add a cancel event or delegate that the thread will subscribe to. When the cancel event is invoke, the thread can stop itself.
I absolutely like Jon Skeets answer. However, this might be a bit easier to understand and should also work:
public class BackgroundTask : IDisposable
{
private readonly CancellationTokenSource cancellationTokenSource;
private bool stop;
public BackgroundTask()
{
this.cancellationTokenSource = new CancellationTokenSource();
this.stop = false;
}
public void Stop()
{
this.stop = true;
this.cancellationTokenSource.Cancel();
}
public void Dispose()
{
this.cancellationTokenSource.Dispose();
}
private void ThreadedWork(object state)
{
using (var syncHandle = new ManualResetEventSlim())
{
while (!this.stop)
{
syncHandle.Wait(TimeSpan.FromMinutes(15), this.cancellationTokenSource.Token);
if (!this.cancellationTokenSource.IsCancellationRequested)
{
// DoWork();
}
}
}
}
}
Or, including waiting for the background task to actually have stopped (in this case, Dispose must be invoked by other thread than the one the background thread is running on, and of course this is not perfect code, it requires the worker thread to actually have started):
using System;
using System.Threading;
public class BackgroundTask : IDisposable
{
private readonly ManualResetEventSlim threadedWorkEndSyncHandle;
private readonly CancellationTokenSource cancellationTokenSource;
private bool stop;
public BackgroundTask()
{
this.threadedWorkEndSyncHandle = new ManualResetEventSlim();
this.cancellationTokenSource = new CancellationTokenSource();
this.stop = false;
}
public void Dispose()
{
this.stop = true;
this.cancellationTokenSource.Cancel();
this.threadedWorkEndSyncHandle.Wait();
this.cancellationTokenSource.Dispose();
this.threadedWorkEndSyncHandle.Dispose();
}
private void ThreadedWork(object state)
{
try
{
using (var syncHandle = new ManualResetEventSlim())
{
while (!this.stop)
{
syncHandle.Wait(TimeSpan.FromMinutes(15), this.cancellationTokenSource.Token);
if (!this.cancellationTokenSource.IsCancellationRequested)
{
// DoWork();
}
}
}
}
finally
{
this.threadedWorkEndSyncHandle.Set();
}
}
}
If you see any flaws and disadvantages over Jon Skeets solution i'd like to hear them as i always enjoy learning ;-)
I guess this is slower and uses more memory and should thus not be used in a large scale and short timeframe. Any other?
I was playing with a project of mine today and found an interesting little snippet, given the following pattern, you can safely cleanup a thread, even if it's forced to close early. My project is a network server where it spawns a new thread for each client. I've found this useful for early termination from the remote side, but also from the local side (I can just call .Abort() from inside my processing code).
Are there any problems you can see with this, or any suggestions you'd make to anyone looking at a similar approach?
Test case follows:
using System;
using System.Threading;
class Program
{
static Thread t1 = new Thread(thread1);
static Thread t2 = new Thread(thread2);
public static void Main(string[] args)
{
t1.Start();
t2.Start();
t1.Join();
}
public static void thread1() {
try {
// Do our work here, for this test just look busy.
while(true) {
Thread.Sleep(100);
}
} finally {
Console.WriteLine("We're exiting thread1 cleanly.\n");
// Do any cleanup that might be needed here.
}
}
public static void thread2() {
Thread.Sleep(500);
t1.Abort();
}
}
For reference, without the try/finally block, the thread just dies as one would expect.
Aborting another thread at all is just a bad idea unless the whole application is coming down. It's too easy to leave your program in an unknown state. Aborting your own thread is occasionally useful - ASP.NET throws a ThreadAbortException if you want to prematurely end the response, for example - but it's not a terribly nice design.
Safe clean-up of a thread should be mutual - there should be some shared flag requesting that the thread shuts down. The thread should check that flag periodically and quit appropriately.
Whether or not this will "safely" cleanup a thread cannot be discerned from a general code sample unfortunately. It's highly dependent upon the actual code that is executed within the thread. There are multiple issues you must consider. Each represents a potential bug in the code.
If the thread is currently in native code, it will not immediately respect the Thread.Abort call. It will do all of the work it wants to do in native code and will not throw until the code returns back to managed. Until this happens thread2 will hang.
Any native resources that are not freed in a finally block will be leaked in this scenario. All native resources should be freed in a finally block but not all code does this and it's an issue to consider.
Any locks that are not freed in a finally block will remain in a lock'd state and can lead to future dead locks.
There are other issues which are slipping my mind at the moment. But hopefully this will give you some guidance with your application.
It is generally not a good idea to abort threads. What you can do is poll for a stopRequested flag which can be set from other threads. Below is a sample WorkerThread class for your reference. For more information on how to use it, please refer to http://devpinoy.org/blogs/jakelite/archive/2008/12/20/threading-patterns-the-worker-thread-pattern.aspx
public abstract class WorkerThreadBase : IDisposable
{
private Thread _workerThread;
protected internal ManualResetEvent _stopping;
protected internal ManualResetEvent _stopped;
private bool _disposed;
private bool _disposing;
private string _name;
protected WorkerThreadBase()
: this(null, ThreadPriority.Normal)
{
}
protected WorkerThreadBase(string name)
: this(name, ThreadPriority.Normal)
{
}
protected WorkerThreadBase(string name,
ThreadPriority priority)
: this(name, priority, false)
{
}
protected WorkerThreadBase(string name,
ThreadPriority priority,
bool isBackground)
{
_disposing = false;
_disposed = false;
_stopping = new ManualResetEvent(false);
_stopped = new ManualResetEvent(false);
_name = name == null ? GetType().Name : name; ;
_workerThread = new Thread(threadProc);
_workerThread.Name = _name;
_workerThread.Priority = priority;
_workerThread.IsBackground = isBackground;
}
protected bool StopRequested
{
get { return _stopping.WaitOne(1, true); }
}
protected bool Disposing
{
get { return _disposing; }
}
protected bool Disposed
{
get { return _disposed; }
}
public string Name
{
get { return _name; }
}
public void Start()
{
ThrowIfDisposedOrDisposing();
_workerThread.Start();
}
public void Stop()
{
ThrowIfDisposedOrDisposing();
_stopping.Set();
_stopped.WaitOne();
}
public void WaitForExit()
{
ThrowIfDisposedOrDisposing();
_stopped.WaitOne();
}
#region IDisposable Members
public void Dispose()
{
dispose(true);
}
#endregion
public static void WaitAll(params WorkerThreadBase[] threads)
{
WaitHandle.WaitAll(
Array.ConvertAll<WorkerThreadBase, WaitHandle>(
threads,
delegate(WorkerThreadBase workerThread)
{ return workerThread._stopped; }));
}
public static void WaitAny(params WorkerThreadBase[] threads)
{
WaitHandle.WaitAny(
Array.ConvertAll<WorkerThreadBase, WaitHandle>(
threads,
delegate(WorkerThreadBase workerThread)
{ return workerThread._stopped; }));
}
protected virtual void Dispose(bool disposing)
{
//stop the thread;
Stop();
//make sure the thread joins the main thread
_workerThread.Join(1000);
//dispose of the waithandles
DisposeWaitHandle(_stopping);
DisposeWaitHandle(_stopped);
}
protected void ThrowIfDisposedOrDisposing()
{
if (_disposing)
{
throw new InvalidOperationException(
Properties.Resources.ERROR_OBJECT_DISPOSING);
}
if (_disposed)
{
throw new ObjectDisposedException(
GetType().Name,
Properties.Resources.ERROR_OBJECT_DISPOSED);
}
}
protected void DisposeWaitHandle(WaitHandle waitHandle)
{
if (waitHandle != null)
{
waitHandle.Close();
waitHandle = null;
}
}
protected abstract void Work();
private void dispose(bool disposing)
{
//do nothing if disposed more than once
if (_disposed)
{
return;
}
if (disposing)
{
_disposing = disposing;
Dispose(disposing);
_disposing = false;
//mark as disposed
_disposed = true;
}
}
private void threadProc()
{
Work();
_stopped.Set();
}
}