Scheduling engine that supports more then just date/time triggers - c#

I have found a number of great .NET scheduling engines, specifically Quartz.Net looks very promising. However, I need a scheduling engine that will allow me to trigger off of not only dates and times but also off of anything I can come up with. For example I might want to trigger when I see a process has started, when the computer is locked, off of a WMI event, etc... in addition to date/time based triggers.
What I am looking for is a solution that will allow me to implement the appropriate interface and fire the trigger whenever my conditions are met. Does something like this already exist or am I on my own?
Here are a couple I looked at:
What is the best way to represent "Recurring Events" in database?
c# recurring event (like for a calendar)
Recommend a C# Task Scheduling Library
How to write C# Scheduler
http://www.codeproject.com/Articles/2478/C-Scheduler
http://www.codeproject.com/Articles/2407/A-New-Task-Scheduler-Class-Library-for-NET
http://www.codeproject.com/Articles/8424/A-component-for-event-scheduling-inside-an-applica
http://blog.bobcravens.com/2009/10/an-event-based-cron-scheduled-job-in-c/
http://www.codeproject.com/Articles/6507/NET-Scheduled-Timer
This needs to run within my .NET application. I looked into modifying Quartz.Net to support this type of triggering but the concept of date/time triggers is just to ingrained; it would probably be easier to write my own scheduler since I don't need to save jobs and triggers to a database.
I'd prefer to work off of an existing scheduling system just so I don't have to worry about implementing the gritty details like queues, priorities, thread pools, etc... but of course I'll do what I have to do.

You could declare a base Task class, or interface, whichever you prefer that implements a bool property NeedsToRun and a method Run().
You could then inherit the Task class for each of your individual tasks (or using delegate funcs, task types) and define all the custom requirements you would need in order to check whether or not that task needs to run, and if it does, call the Run() method of that specific task.
Add all your tasks to a List<Task> and iterate over them periodically to see which task actually need running, and voila; you have a very simple, but effective scheduler.
Personally, I was after a priority-based scheduler rather than an event-driven one as you describe, so I implemented a Func<bool> to determine whether a task needs to run and an Action to actually run it. My code is as follows:
public class Task : IComparable<Task>
{
public Task(int priority, Action action, Func<bool> needsToRun, string name = "Basic Task")
{
Priority = priority;
Name = name;
Action = action;
_needsToRun = needsToRun;
}
public string Name { get; set; }
public int Priority { get; set; }
private readonly Func<bool> _needsToRun;
public bool NeedsToRun { get { return _needsToRun.Invoke(); } }
/// <summary>
/// Gets or sets the action this task performs.
/// </summary>
/// <value>
/// The action.
/// </value>
public Action Action { get; set; }
public void Run()
{
if (Action != null)
Action.Invoke();
}
#region Implementation of IComparable<in State>
/// <summary>
/// Compares the current object with another object of the same type.
/// </summary>
/// <returns>
/// A value that indicates the relative order of the objects being compared. The return value has the following meanings: Value Meaning Less than zero This object is less than the <paramref name="other"/> parameter.Zero This object is equal to <paramref name="other"/>. Greater than zero This object is greater than <paramref name="other"/>.
/// </returns>
/// <param name="other">An object to compare with this object.</param>
public int CompareTo(Task other)
{
return Priority == other.Priority && Name == other.Name ? 1 : 0;
}
#endregion
}
But I reckon this could be adapted to subscribe to events and setting a flag to make sure NeedsToRun returns true whenever that event is fired fairly easily.

Related

C# delegates to Java and asynchronous handling of methods

I have been tasked with creating Java code with similar functionality to the code below. Currently I am struggling with understanding exactly what the code does and how to simulate the effect in Java.
#region "Send Aggregate Event"
/// <summary>
/// Delegate for async sending the AggregateEvent
/// </summary>
/// <param name="request"></param>
public delegate void SendAggregateEventAsync(AE request);
SendAggregateEventAsync _sendAggregateEventAsync;
/// <summary>
/// IAsyncResult pattern to async send the AggregateEvent
/// </summary>
/// <param name="request"></param>
/// <param name="callback"></param>
/// <param name="state"></param>
/// <returns></returns>
public IAsyncResult BeginSendAggregateEvent(AE request, AsyncCallback callback, Object state)
{
_sendAggregateEventAsync = new SendAggregateEventAsync(SendAggregateEvent);
return _sendAggregateEventAsync.BeginInvoke(request, callback, state);
}
public void EndSendAggregateEvent(IAsyncResult result)
{
object state = result.AsyncState;
_sendAggregateEventAsync.EndInvoke(result);
}
/// <summary>
/// Send an aggregate event to the Device Webserver
/// </summary>
/// <param name="request">The AggregateEvent request</param>
public void SendAggregateEvent(AE request)
{
if (request == null) throw new ArgumentNullException("request");
String message = ChangeDatesToUTC(MessageHelper.SerializeObject( typeof(AE), request), new String[] { "EventTime" }, url);
SendMessage(message);
}
#endregion
There are several other events all with similar code to the provided above. From the comments, I understand that the code is intended to asynchronously handle the SendAggregateEvent method. What I do not understand is why the delegate modifier is used, or how to replicate this type of asynchronous handling in Java.
Also from reading this thread
Java Delegates?
I understand that there is no "easy" way to simulate the delegate functionality in java. Is it necessary to have the delegate functionality to have the SendAggregateEvent method handled asynchronously? If not, can someone suggest how I would do this?
This is actually the old way of writing async code in C#, commonly referred to as the Async Programming Model
I am not familiar enough with java, but all you really need to replicate this code is to create a method that does the action synchronously SendAggregateEvent and a means to call that asynchronously SendAggregateEventAsync
More specifically to some of your questions. The delegate is only being used to encapsulate the SendAggregateEvent method so that it and its parameters can be invoked on a potentially different thread (keeping in mind that async is not necessarily multi-threaded)
It goes something like this:
var referenceToTaskBeingRun = BeginSomeMethod()
//the above wraps the actual method and calls it, returning a reference to the task
var results = EndSomeMethod(referenceToTaskBeingRun );
//the above sends the reference so that it can be used to get the results from the task.
//NOTE that this is blocking because you are now waiting for the results, whether they finished or not
The preferred way to do this now is to use the Task Parallel Library, which has a much easier to read code base.
So, all of that being said, the key to focus on this code would be that you just need a method and an async version of that method. The implementation should be up to you and your programming stack. Do not try to force another stack's implementation where it does not belong...especially an implementation that is not even the preferred methodology any longer.
According to How to asynchronously call a method in Java's answer, FutureTask is a good way in Java to asynchronously run a method. Here's some Java code that runs a task asynchronously (see it run at http://ideone.com/ZtjA5C)
import java.util.*;
import java.lang.*;
import java.util.concurrent.FutureTask;
class Main
{
public static void main (String[] args) throws java.lang.Exception
{
System.out.println("Before");
ExecutorService executorService = Executors.newFixedThreadPool(1);
FutureTask<Object> futureTask = new FutureTask<Object>(new Runnable() {
public void run()
{
System.out.println("Hello async world!");
}
}, null);
System.out.println("Defined");
executorService.execute(futureTask);
System.out.println("Running");
while (!futureTask.isDone())
{
System.out.println("Task not yet completed.");
try
{
Thread.sleep(1);
}
catch (InterruptedException interruptedException)
{
}
}
System.out.println("Done");
}
}

Form does not work unless .Show() is called

I have a form that represents a USB device Terminal that has been giving me some errors. After half a day of debugging strange errors with no known source I somehow found out that the Terminal does not function when it is instantiated but not shown. When I change the code and add usbTerminal.Show();, then it works properly.
USBTerminal usbTouchTerminal;
public MainForm()
{
InitializeComponent();
USBSettings usbTouchSettings = new USBSettings();
usbTouchTerminal = new USBTerminal(usbTouchSettings); //Create Terminal with settings
usbTouchTerminal.StartUSB();
usbTouchTerminal.Show(); //works ONLY when show is here
}
How is this possible and why? I've done a massive search and none of my code depends on the .Visible property on either my Terminal or main form?
I'm completely baffled on why some form would not work if it isn't shown. MSDN or google wasn't really a help either. I was certain it would function properly when instantiated but not shown.
PS. I added
usbTerminal.Show();
usbTerminal.Hide();
and the Terminal functioned correctly.
Thank you for any help!
EDIT:
I should also note that this usbTerminal uses the WndProc override. I'm not an expert on that, but I feel that it may have something to do with it.
I should note that this is LibUSBdotnet
public class USBSettings
{
/// <summary>
/// This is the Vender ID Number. (0x0B6A)
/// </summary>
public ushort VID { get; set; }
/// <summary>
/// This is the Product ID Number. (0x5346)
/// </summary>
public ushort PID { get; set; }
/// <summary>
/// This is the optional Serial Name. ("")
/// </summary>
public string SerialName { get; set; }
/// <summary>
/// This is the Reader USB Endpoint. (ReadEndpointID.Ep02)
/// </summary>
public ReadEndpointID ReaderEndpoint { get; set; }
/// <summary>
/// This is the Writer USB Endpoint. (WriteEndpointID.Ep01)
/// </summary>
public WriteEndpointID WriterEndpoint { get; set; }
/// <summary>
/// This is the Registry Key for USB settings. ("SOFTWARE\\DEFAULT\\USBPROPERTIES")
/// </summary>
public string SubKey { get; set; }
/// <summary>
/// This is the default read buffer size for the USB Device.
/// </summary>
public int ReadBufferSize { get; set; }
/// <summary>
/// This constructor houses default values for all properties.
/// </summary>
public USBSettings()
{
VID = 0x0B6A;
PID = 0x5346;
SerialName = "";
ReaderEndpoint = ReadEndpointID.Ep02;
WriterEndpoint = WriteEndpointID.Ep01;
SubKey = "SOFTWARE\\DEFAULT\\USBPROPERTIES";
ReadBufferSize = 100;
}
}
The question is poorly documented but this is fairly normal for code that works with devices. They tend to need to know about Plug & Play events and that requires a top-level window to be created that receives the WM_DEVICECHANGE notification message. Creating a .NET Form object isn't enough, you also have to create the native window for it. Which, in typical .NET lazy fashion, happens at the last possible moment, when you force the window to be visible. Either by calling the Show() method or setting the Visible property to true. The window doesn't actually have to be visible to get the Plug & Play notifications.
You can get the window created without also making it visible. That requires modifying the USBTerminal class. Paste this code:
protected override void SetVisibleCore(bool value) {
if (!this.IsHandleCreated) {
this.CreateHandle();
value = false;
}
base.SetVisibleCore(value);
}
And call the Show() method as normal. Beware that the Load event won't fire until the window actually becomes visible so if necessary move any code in the event handler to this method. If this is not the primary window for the app, in other words not the one that's passed to Application.Run() in your Main() method, then you can make do with simply calling this.CreateHandle() as the last statement in the form constructor. In which case calling Show() is no longer necessary.
I suspect this is because the underlying window is not created before you call Show(). Since the window isn't created, your custom WndProc isn't called.
To verify, you can create the window without showing it - by looking at the Handle property. As the documentation says - if the handle has not been created by the time you call, it will be created. Try it, I bet it'll work just as if you called Show and then Hide.
It is very hard to tell from the information you have but I think you are using a form where a class should be used. You should rethink your program structure and re-write this as a class to hold and transmit the data as you need. As some of the other have pointed out the listbox and/or other function are not running until the form is shown and the methods is executed.
Because some required functions will be called when Form onShow event called.

Using BlockingCollection<T>: OperationCanceledException, is there a better way?

I'm making use of the (frankly great) BlockingCollection<T> type for a heavily multithreaded, high-performance app.
There's a lot of throughput through the collection and on the micro-level it's highly performant. However, for each 'batch' it will always be ended by flagging the cancellation token. This results in an exception being thrown on any waiting Take call. That's fine, but I would have settled for a return value or output parameter to signal it, because a) exceptions have an obvious overhead and b) when debugging, I don't want to manually turn off break-on-exception for that specific exception.
The implementation seems intense, and in theory I suppose I could disassemble and recreate my own version that didn't use exceptions, but perhaps there's a less complex way?
I could add a null (or if not, a placeholder) object to the collection to signify the process should end, however there also needs to be a means to abort nicely, i.e. wake up waiting threads and tell them somehow that something's gone on.
So - alternative collection types? Recreate my own? Some way to abuse this one?
(Some context: I went with BlockingCollection<T> because it has an advantage over manual locking around a Queue. As best I can tell the use of threading primitives is superb and in my case, a few milliseconds here-and-there and optimal core is use crucial.)
Edit: I've just opened a bounty for this one. I don't believe Anastasiosyal's answer covers the query I raise in my comment of it. I know this is a tough problem. Is anyone able to assist?
As I guess you have already done yourself, looking into the reflected source of BlockingCollection it looks unfortunately that when a CancellationToken is passed into the BlockingCollection and it cancels then you will get the OperationCancelledException as can be seen in the image below (with a couple of workarounds after the image)
GetConsumingEnumerable invokes TryTakeWithNoTimeValidation on the BlockingCollection which in turn raises this exception.
Workaround #1
One potential strategy would be, assuming you have more control over your producers and your consumers, rather than pass the cancellation token into the BlockingCollection, (which will raise this exception) you pass the cancellation token into your producers and into your consumers.
If your producers aren't producing and your consumers aren't consuming, then you have effectively cancelled the operation without raising this exception and by passing CancellationToken.None in your BlockingCollection.
Special cases Cancelling when the BlockingCollection is at BoundedCapacity or Empty
Producers blocked: The producer threads will be blocked when BoundedCapacity on the BlockingCollection is reached. Hence, when attempting to cancel and the BlockingCollection is at BoundedCapacity (which means that your consumers are not blocked but producers are blocked because they cannot add any additional items to the queue) then you will need to allow for additional items to be consumed (one for each producer thread) that will unblock the producers (because they are blocked on adding to the blockingCollection) and in turn allow for your cancellation logic to kick in on the producer side.
Consumers blocked: When your consumers are blocked because the queue is empty, then you could insert an empty unit of work (one for each consumer thread) in the Blocking collection so as to unblock the consumer threads and allow for your cancellation logic to kick in the consumer side.
When there are items in the queue and no limit such as BoundedCapacity or Empty has been reached then the producers and consumer threads should not be blocked.
Workaround #2
Using a cancellation unit of work.
When your application needs to cancel, then your producers (maybe just 1 producer will suffice while the others just cancel producing) will produce a cancellation unit of work (could be null as you also mention or some class that implements a marker interface). When the consumers consume this unit of work and detect that it is in fact a cancellation unit of work, their cancellation logic kicks in. The number of cancellation units of work to be produced needs to equal the number of consumer threads.
Again, caution is needed when we are close to BoundedCapacity, as it could be a sign that some of the producers are blocked. Depending on the number of producers/consumers you could have a consumer consuming until all producers (but 1) have shut down. This ensures that there are no lingering producers around. When there is only 1 producer left, your last consumer can shut down and the producer can stop producing cancellation units of work.
How about the BlockingQueue I did a while ago?
http://apichange.codeplex.com/SourceControl/changeset/view/76c98b8c7311#ApiChange.Api%2fsrc%2fInfrastructure%2fBlockingQueue.cs
It should do fine without any exceptions. The current queue does simply close the event on dispose which might not be what you want. You might want do enque a null and wait until all items were processed. Apart from this it should suit your needs.
using System.Collections.Generic;
using System.Collections;
using System.Threading;
using System;
namespace ApiChange.Infrastructure
{
/// <summary>
/// A blocking queue which supports end markers to signal that no more work is left by inserting
/// a null reference. This constrains the queue to reference types only.
/// </summary>
/// <typeparam name="T"></typeparam>
public class BlockingQueue<T> : IEnumerable<T>, IEnumerable, IDisposable where T : class
{
/// <summary>
/// The queue used to store the elements
/// </summary>
private Queue<T> myQueue = new Queue<T>();
bool myAllItemsProcessed = false;
ManualResetEvent myEmptyEvent = new ManualResetEvent(false);
/// <summary>
/// Deques an element from the queue and returns it.
/// If the queue is empty the thread will block. If the queue is stopped it will immedieately
/// return with null.
/// </summary>
/// <returns>An object of type T</returns>
public T Dequeue()
{
if (myAllItemsProcessed)
return null;
lock (myQueue)
{
while (myQueue.Count == 0)
{
if(!Monitor.Wait(myQueue, 45))
{
// dispatch any work which is not done yet
if( myQueue.Count > 0 )
continue;
}
// finito
if (myAllItemsProcessed)
{
return null;
}
}
T result = myQueue.Dequeue();
if (result == null)
{
myAllItemsProcessed = true;
myEmptyEvent.Set();
}
return result;
}
}
/// <summary>
/// Releases the waiters by enqueuing a null reference which causes all waiters to be released.
/// The will then get a null reference as queued element to signal that they should terminate.
/// </summary>
public void ReleaseWaiters()
{
Enqueue(null);
}
/// <summary>
/// Waits the until empty. This does not mean that all items are already process. Only that
/// the queue contains no more pending work.
/// </summary>
public void WaitUntilEmpty()
{
myEmptyEvent.WaitOne();
}
/// <summary>
/// Adds an element of type T to the queue.
/// The consumer thread is notified (if waiting)
/// </summary>
/// <param name="data_in">An object of type T</param>
public void Enqueue(T data_in)
{
lock (myQueue)
{
myQueue.Enqueue(data_in);
Monitor.PulseAll(myQueue);
}
}
/// <summary>
/// Returns an IEnumerator of Type T for this queue
/// </summary>
/// <returns></returns>
IEnumerator<T> IEnumerable<T>.GetEnumerator()
{
while (true)
{
T item = Dequeue();
if (item == null)
break;
else
yield return item;
}
}
/// <summary>
/// Returns a untyped IEnumerator for this queue
/// </summary>
/// <returns></returns>
IEnumerator IEnumerable.GetEnumerator()
{
return ((IEnumerable<T>)this).GetEnumerator();
}
#region IDisposable Members
/// <summary>
/// Closes the EmptyEvent WaitHandle.
/// </summary>
public void Dispose()
{
myEmptyEvent.Close();
}
#endregion
}
}
You cound signal the end of a batch by setting a flag on the last item (add a IsLastItem bool property to it or wrap it). Or you might send a null as last item (not sure if a null goes through the blockingcollection correctly though).
If you can remove the need for the 'batch' concept you can create an extra thread to continously Take() and Process new Data from your blockingcollection and do nothing else.
Kieren,
From my inspection, I personally don't know any thread safe type for ProducerConsumer pattern which does exactly what you wanted. I don't claim this as competitive solution but propose you decorate BlockingCollection<T> with few extension method which will give you the freedom to supply any built-in or custom types instead of default CancellationToken.
Stage 1:
Following are the list of default method which use underling TryAddWithNoTimeValidation method to add to queue.
public void Add(T item){
this.TryAddWithNoTimeValidation(item, -1, new CancellationToken());
}
public void Add(T item, CancellationToken cancellationToken){
this.TryAddWithNoTimeValidation(item, -1, cancellationToken);
}
public bool TryAdd(T item){
return this.TryAddWithNoTimeValidation(item, 0, new CancellationToken());
}
public bool TryAdd(T item, TimeSpan timeout){
BlockingCollection<T>.ValidateTimeout(timeout);
return this.TryAddWithNoTimeValidation(item, (int) timeout.TotalMilliseconds, new CancellationToken());
}
public bool TryAdd(T item, int millisecondsTimeout){
BlockingCollection<T>.ValidateMillisecondsTimeout(millisecondsTimeout);
return this.TryAddWithNoTimeValidation(item, millisecondsTimeout, new CancellationToken());
}
public bool TryAdd(T item, int millisecondsTimeout, CancellationToken cancellationToken){
BlockingCollection<T>.ValidateMillisecondsTimeout(millisecondsTimeout);
return this.TryAddWithNoTimeValidation(item, millisecondsTimeout, cancellationToken);
}
Now you can provide extension for any/all of method which you are interested.
Stage 2:
You now refer your implementation of TryAddWithNoTimeValidation instead of default.
I can give you an alternate version of TryAddWithNoTimeValidation which safely continue without throwing OperationCancellation exception.
My suggestion is to implement this functionality by encapsulating an asynchronous queue, like the BufferBlock<T> class from the TPL Dataflow library. This class is a thread-safe container intended for producer-consumer scenarios, and supports backpressure (BoundedCapacity) just like the BlockingCollection<T> class. Being asynchronous means that the corresponding Add/Take methods (SendAsync/ReceiveAsync) return tasks. These tasks store the event of a cancellation as an internal state, that can be queried with the IsCanceled property, so throwing exceptions internally can be avoided. Propagating this state with exceptions can also be avoided, by waiting the tasks using a exception-suppressing continuation (ContinueWith). Here is an implementation:
/// <summary>
/// A thread-safe collection that provides blocking and bounding capabilities.
/// The cancellation is propagated as a false result, and not as an exception.
/// </summary>
public class CancellationFriendlyBlockingCollection<T>
{
private readonly BufferBlock<T> _bufferBlock;
public CancellationFriendlyBlockingCollection()
{
_bufferBlock = new BufferBlock<T>();
}
public CancellationFriendlyBlockingCollection(int boundedCapacity)
{
_bufferBlock = new BufferBlock<T>(new() { BoundedCapacity = boundedCapacity });
}
public bool TryAdd(T item, CancellationToken cancellationToken = default)
{
if (cancellationToken.IsCancellationRequested) return false;
if (_bufferBlock.Post(item)) return true;
Task<bool> task = _bufferBlock.SendAsync(item, cancellationToken);
WaitNoThrow(task);
if (!task.IsCompletedSuccessfully) return false;
return task.Result;
}
public bool TryTake(out T item, CancellationToken cancellationToken = default)
{
if (cancellationToken.IsCancellationRequested) { item = default; return false; }
if (_bufferBlock.TryReceive(out item)) return true;
Task<T> task = _bufferBlock.ReceiveAsync(cancellationToken);
WaitNoThrow(task);
if (!task.IsCompletedSuccessfully) return false;
item = task.Result; return true;
}
public IEnumerable<T> GetConsumingEnumerable(
CancellationToken cancellationToken = default)
{
while (TryTake(out var item, cancellationToken)) yield return item;
}
public void CompleteAdding() => _bufferBlock.Complete();
public bool IsCompleted => _bufferBlock.Completion.IsCompleted;
public int Count => _bufferBlock.Count;
// Wait the task to complete without throwing exceptions
private static void WaitNoThrow(Task task)
{
if (task.IsCompleted) return;
task.ContinueWith(_ => { }, default,
TaskContinuationOptions.ExecuteSynchronously |
TaskContinuationOptions.DenyChildAttach, TaskScheduler.Default).Wait();
Debug.Assert(task.IsCompleted);
}
}
Performance: The CancellationFriendlyBlockingCollection.TryTake method can be invoked with a canceled CancellationToken in a loop with a frequency of about 15,000,000 times per second in my PC (on a single thread). For comparison the frequency of the BlockingCollection<T>.Take under the same conditions is about 20,000 times per second.
You might be tempted to replace the BufferBlock<T> with a more modern asynchronous queue like the Channel<T>. In that case please make sure to read this question first, in order to be aware about a leaky behavior of this class, under specific conditions.

WatiN Parallelization within a test

I have a test where I want to ensure separate operations within one page result in distinct results. Specifically, I have a few ways to sort on a page and I want a test to make sure that each sort is different. I have other tests to ensure the correctness of each sort.
I would like the focus of this conversation to be on a good way to run test operations in parallel and compare the results at the end, rather than on what to test or testing methods. I figure parallel operations in testing is an interesting and broad enough topic that it could be useful to others.
Let "generateHashFromSearchResults()" be a function that returns a string representing the order of the search results shown on current IE instance. Here is what the working code looks like in a serialized fashion using one browser instance:
var set = new HashSet<string>();
var sortOptions = new List<String>() { "sort1", "sort2", "sort3" };
// Default sort
set.Add(generateHashFromSearchResults());
sortOptions.ForEach(s => {
ie.Link(Find.ByText(s)).Click();
set.Add(generateHashFromSearchResults());
});
Assert.That(set.Count() == 4);
I had read about PLINQ a few months ago and figured this might be a decent use case. Now let "generateHashFromSearchResults(IE ie)" be the same function, but that operates on an explicitly defined IE instance. I tried something like this:
List<string> resultList = sortOptions.AsParallel().Select(s => {
var ie = new IE(true);
ie.Link(Find.ByText(s)).Click();
return generateHashFromSearchResults(ie);
}).ToList();
// Forget about default sort for now. There should be 3 distinct results
Assert.That(new HashSet<string>(resultList).Count() == 3);
The biggest issue I face right now is not understanding how PLINQ does thread management. WatiN needs to run with the apartment state set to single threaded (STAThread). I get that each IE instance should be in its own thread, but no amount of setting each thread in the PLINQ query to the proper apartment state fixes the issue.
I'm starting to suspect that I either need to learn more about PLINQ to continue, or that I need to learn more about thread management by hand to get this to work.
Any thoughts?
You can't specify a custom scheduler with AsParallel(). But you can create a Task for each sort option and pass an instance of a custom scheduler into the Start() method. This implementation of an STA Thread scheduler was borrowed from Stephen Toub (http://blogs.msdn.com/b/pfxteam/archive/2010/04/07/9990421.aspx):
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
/// <summary>
/// Provides a scheduler that uses STA threads.
/// Borrowed from Stephen Toub's implementation http://blogs.msdn.com/b/pfxteam/archive/2010/04/07/9990421.aspx
/// </summary>
public sealed class StaTaskScheduler : TaskScheduler, IDisposable
{
/// <summary>
/// The STA threads used by the scheduler.
/// </summary>
private readonly List<Thread> threads;
/// <summary>
/// Stores the queued tasks to be executed by our pool of STA threads.
/// </summary>
private BlockingCollection<Task> tasks;
/// <summary>
/// Initializes a new instance of the StaTaskScheduler class with the specified concurrency level.
/// </summary>
/// <param name = "numberOfThreads">The number of threads that should be created and used by this scheduler.</param>
public StaTaskScheduler(int numberOfThreads)
{
if (numberOfThreads < 1)
{
throw new ArgumentOutOfRangeException(
"numberOfThreads", "The scheduler must create at least one thread");
}
// Initialize the tasks collection
this.tasks = new BlockingCollection<Task>();
// Create the threads to be used by this scheduler
this.threads = Enumerable.Range(0, numberOfThreads).Select(
i =>
{
var thread = new Thread(
() =>
{
// Continually get the next task and try to execute it.
// This will continue until the scheduler is disposed and no more tasks remain.
foreach (Task t in this.tasks.GetConsumingEnumerable())
{
this.TryExecuteTask(t);
}
}) {
Name = "Sta Thread", IsBackground = true
};
thread.SetApartmentState(ApartmentState.STA);
return thread;
}).ToList();
// Start all of the threads
this.threads.ForEach(t => t.Start());
}
/// <summary>
/// Gets the maximum concurrency level supported by this scheduler.
/// </summary>
public override int MaximumConcurrencyLevel
{
get
{
return this.threads.Count;
}
}
/// <summary>
/// Cleans up the scheduler by indicating that no more tasks will be queued.
/// This method blocks until all threads successfully shutdown.
/// </summary>
public void Dispose()
{
if (this.tasks != null)
{
// Indicate that no new tasks will be coming in
this.tasks.CompleteAdding();
// Wait for all threads to finish processing tasks
foreach (Thread thread in this.threads)
{
thread.Join();
}
// Cleanup
this.tasks.Dispose();
this.tasks = null;
}
}
/// <summary>
/// Provides a list of the scheduled tasks for the debugger to consume.
/// </summary>
/// <returns>An enumerable of all tasks currently scheduled.</returns>
protected override IEnumerable<Task> GetScheduledTasks()
{
// Serialize the contents of the blocking collection of tasks for the debugger
return this.tasks.ToArray();
}
/// <summary>
/// Queues a Task to be executed by this scheduler.
/// </summary>
/// <param name = "task">The task to be executed.</param>
protected override void QueueTask(Task task)
{
// Push it into the blocking collection of tasks
this.tasks.Add(task);
}
/// <summary>
/// Determines whether a Task may be inlined.
/// </summary>
/// <param name = "task">The task to be executed.</param>
/// <param name = "taskWasPreviouslyQueued">Whether the task was previously queued.</param>
/// <returns>true if the task was successfully inlined; otherwise, false.</returns>
protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
{
// Try to inline if the current thread is STA
return Thread.CurrentThread.GetApartmentState() == ApartmentState.STA && this.TryExecuteTask(task);
}
}
Maybe You should use Task Parallel Library?
I'm a beginner in TPL, but there are Schedulers that maybe have some options for setting STAThread on scheduled Tasks.

Best solution for a windows service with constant running threads in C# 4.0

I want to create a windows service that will create x number of threads that wake up every x number of minutes and do some work.
I think the task scheduling or parallel framework is a bad fit for this type of work as it is best suited for work that starts, completes and finishes rather than is constant.
Should I look at utilising a thread pool for this approach or does anyone have any advice for a good solution?
Really, it sounds like you only need one thread.
Here's a helper class that I created for exactly this kind of thing. Here's how you use it:
class MyPeriodicTasks : PeriodicMultiple
{
// The first task will start 30 seconds after this class is instantiated and started:
protected override TimeSpan FirstInterval { get { return TimeSpan.FromSeconds(30); } }
public MyPeriodicTasks()
{
Tasks = new[] {
new Task { Action = task1, MinInterval = TimeSpan.FromMinutes(5) },
new Task { Action = task2, MinInterval = TimeSpan.FromMinutes(15) },
};
}
private void task1() { /* code that gets executed once every 5 minutes */ }
private void task2() { /* code that gets executed once every 15 minutes */ }
}
Then, to start the tasks:
var tasks = new MyPeriodicTasks();
tasks.Start();
And during service shutdown:
tasks.Shutdown();
(alternatively, call Start with backgroundThread: true, then you don't need to call Shutdown, but then a task may just get terminated right in the middle of doing something)
Here's the actual code:
/// <summary>
/// Encapsulates a class performing a certain activity periodically, which can be initiated once
/// and then permanently shut down, but not paused/resumed. The class owns its own separate
/// thread, and manages this thread all by itself. The periodic task is executed on this thread.
/// <para>The chief differences to <see cref="System.Threading.Timer"/> are as follows. This
/// class will never issue overlapping activities, even if an activity takes much longer than the interval;
/// the interval is between the end of the previous occurrence of the activity and the start of the next.
/// The activity is executed on a foreground thread (by default), and thus will complete once started,
/// unless a catastrophic abort occurs. When shutting down the activity, it's possible to wait until the
/// last occurrence, if any, has completed fully.</para>
/// </summary>
public abstract class Periodic
{
private Thread _thread;
private CancellationTokenSource _cancellation;
private ManualResetEvent _exited;
/// <summary>
/// Override to indicate how long to wait between the call to <see cref="Start"/> and the first occurrence
/// of the periodic activity.
/// </summary>
protected abstract TimeSpan FirstInterval { get; }
/// <summary>
/// Override to indicate how long to wait between second and subsequent occurrences of the periodic activity.
/// </summary>
protected abstract TimeSpan SubsequentInterval { get; }
/// <summary>
/// Override with a method that performs the desired periodic activity. If this method throws an exception
/// the thread will terminate, but the <see cref="LastActivity"/> will occur nevertheless.
/// </summary>
protected abstract void PeriodicActivity();
/// <summary>
/// Override with a method that performs an activity on the same thread as <see cref="PeriodicActivity"/> during
/// shutdown, just before signalling that the shutdown is complete. The default implementation of this method
/// does nothing. This method is guaranteed to be called during a shutdown, even if the shutdown is due to an
/// exception propagating outside of <see cref="PeriodicActivity"/>.
/// </summary>
protected virtual void LastActivity() { }
/// <summary>
/// Returns false before the first call to <see cref="Start"/> and after the first call to <see cref="Shutdown"/>;
/// true between them.
/// </summary>
public bool IsRunning { get { return _cancellation != null && !_cancellation.IsCancellationRequested; } }
/// <summary>
/// Schedules the periodic activity to start occurring. This method may only be called once.
/// </summary>
/// <param name="backgroundThread">By default (false) the class will use a foreground thread, preventing application shutdown until the thread has terminated. If true, a background thread will be created instead.</param>
public virtual void Start(bool backgroundThread = false)
{
if (_thread != null)
throw new InvalidOperationException(string.Format("\"Start\" called multiple times ({0})", GetType().Name));
_exited = new ManualResetEvent(false);
_cancellation = new CancellationTokenSource();
_thread = new Thread(threadProc) { IsBackground = backgroundThread };
_thread.Start();
}
private volatile bool _periodicActivityRunning = false;
/// <summary>
/// Causes the periodic activity to stop occurring. If called while the activity is being performed,
/// will wait until the activity has completed before returning. Ensures that <see cref="IsRunning"/>
/// is false once this method returns.
/// </summary>
public virtual bool Shutdown(bool waitForExit)
{
if (waitForExit && _periodicActivityRunning && Thread.CurrentThread.ManagedThreadId == _thread.ManagedThreadId)
throw new InvalidOperationException("Cannot call Shutdown(true) from within PeriodicActivity() on the same thread (this would cause a deadlock).");
if (_cancellation == null || _cancellation.IsCancellationRequested)
return false;
_cancellation.Cancel();
if (waitForExit)
_exited.WaitOne();
return true;
}
private void threadProc()
{
try
{
_cancellation.Token.WaitHandle.WaitOne(FirstInterval);
while (!_cancellation.IsCancellationRequested)
{
_periodicActivityRunning = true;
PeriodicActivity();
_periodicActivityRunning = false;
_cancellation.Token.WaitHandle.WaitOne(SubsequentInterval);
}
}
finally
{
try { LastActivity(); }
finally { _exited.Set(); }
}
}
}
/// <summary>
/// <para>Encapsulates a class performing multiple related yet independent tasks on the same thread
/// at a certain minimum interval each. Schedules the activity that is the most late at every opportunity,
/// but will never execute more than one activity at a time (as they all share the same thread).</para>
/// </summary>
public abstract class PeriodicMultiple : Periodic
{
/// <summary>
/// Used to define the activities to be executed periodically.
/// </summary>
protected sealed class Task
{
/// <summary>The activity to be performed.</summary>
public Action Action;
/// <summary>The mimimum interval at which this activity should be repeated. May be delayed arbitrarily though.</summary>
public TimeSpan MinInterval;
/// <summary>Stores the last time this activity was executed.</summary>
public DateTime LastExecuted;
/// <summary>Calculates by how much this activity has been delayed. Is used internally to pick the next activity to run. Returns negative values for activities that aren't due yet.</summary>
public TimeSpan DelayedBy()
{
if (LastExecuted == default(DateTime))
return TimeSpan.FromDays(1000) - MinInterval; // to run shortest interval first when none of the tasks have ever executed
else
return (DateTime.UtcNow - LastExecuted) - MinInterval;
}
}
/// <summary>If desired, override to provide a custom interval at which the scheduler
/// should re-check whether any activity is due to start. Defaults to 1 second.</summary>
protected override TimeSpan SubsequentInterval { get { return TimeSpan.FromSeconds(1); } }
/// <summary>Initialise this with the list of activities to be executed.</summary>
protected IList<Task> Tasks;
/// <summary>For internal use.</summary>
protected sealed override void PeriodicActivity()
{
TimeSpan maxDelay = TimeSpan.MinValue;
Task maxDelayTask = null;
foreach (var task in Tasks)
{
var delayedBy = task.DelayedBy();
if (maxDelay < delayedBy && delayedBy > TimeSpan.Zero)
{
maxDelay = delayedBy;
maxDelayTask = task;
}
}
if (maxDelayTask != null)
{
maxDelayTask.LastExecuted = DateTime.UtcNow;
maxDelayTask.Action();
}
}
}
The thread spends most of the time sleeping, but it does wake up every 1 second to check if a task is due. This 1 second interval is probably too short for intervals like 15 minutes, so reduce it to something like 30 seconds instead (that would be the SubsequentInterval).
Hope it's useful!
It makes very little sense to start x threads to do x jobs when you intentionally don't let them do any work at all for y minutes. Just have one thread do x jobs. It will take x times longer to complete the work (a bit less, actually) but that's no issue at all as long as that takes less than y minutes.
Additional benefits from this is that the service cannot easily impact the responsiveness of the machine, other cores remain available. And that your code becomes a heckofalot easier to implement and debug.
Use the System.Threading.Thread timer to activate the work. The callback runs on a threadpool thread. Starting and stopping the service is easy, just enable/disable that timer.
Do you really need those threads to run constantly and then wake up after x minutes? I think you may want to consider using an existing scheduler library like Quartz.NET which handle running the tasks for you.
I have two suggestions for you. First, for building your service, check out TopShelf. It removes all the pain of setting up a Windows service.
Second, you can use the Observable class to create a timer without resorting to writing Timer specific code or Quartz (a pain to configure!).
Here's some sample code:
public class MyService
{
private IDisposable Timer;
public void Start()
{
Timer = ObservableHelpers
.CreateMinutePulse(15) // check every 15 seconds if it's a new minute
.Subscribe(i => DoSomething());
}
public void Stop()
{
if(Timer != null)
{
Timer.Dispose();
Timer = null;
}
}
public void DoSomething()
{
// do your thing here
}
}
public static class ObservableHelpers
{
/// <summary>
/// Returns an observable that pulses every minute with the specified resolution.
/// The pulse occurs within the amount of time specified by the resolution (in seconds.)
/// Higher resolution (i.e. lower specified number of seconds) may affect execution speed.
/// </summary>
/// <returns></returns>
public static IObservable<int> CreateMinutePulse(int resolution)
{
return Observable
.Interval(TimeSpan.FromSeconds(resolution.SetWithinRange(1, 59)))
.Select(i => DateTime.Now.Minute)
.DistinctUntilChanged();
}
}
Well, I belive your problem seems to be solved with Producer Consumer Design pattern.
Producer will be the single main thread, and the all other threads will be the consumer thread.
From my opinion it will be best have independent threads than using thread pool.
Eg:
private Thread Worker;
public Consumer()
{
Worker = new Thread(ProcessMethod);
}
Now in processmethod you do what you have to do.
Create as many Consumer as you want.

Categories

Resources