Getting a slice of idle processing in managed component under unmanaged host - c#

I have a managed component written in C#, which is hosted by a legacy Win32 app as an ActiveX control. Inside my component, I need to be able to get what normally would be Application.Idle event, i.e. obtain a time slice of the idle processing time on the UI thread (it has to be the main UI thread).
However in this hosted scenario, Application.Idle doesn't get fired, because there is no managed message loop (i.e., no Application.Run).
Sadly, the host also doesn't implement IMsoComponentManager, which might be suitable for what I need. And a lengthy nested message loop (with Application.DoEvents) is not an option for many good reasons.
So far, the only solution I can think of is to use plain Win32 timers.
According to this (now perished) MSKB article, WM_TIMER has one of the lowest priorities, followed only by WM_PAINT, which should get me as close to the idle as possible.
Am I missing any other options for this scenario?
Here is a prototype code:
// Do the idle work in the async loop
while (true)
{
token.ThrowIfCancellationRequested();
// yield via a low-priority WM_TIMER message
await TimerYield(DELAY, token); // e.g., DELAY = 50ms
// check if there is a pending user input in Windows message queue
if (Win32.GetQueueStatus(Win32.QS_KEY | Win32.QS_MOUSE) >> 16 != 0)
continue;
// do the next piece of the idle work on the UI thread
// ...
}
// ...
static async Task TimerYield(int delay, CancellationToken token)
{
// All input messages are processed before WM_TIMER and WM_PAINT messages.
// System.Windows.Forms.Timer uses WM_TIMER
// This could be further improved to re-use the timer object
var tcs = new TaskCompletionSource<bool>();
using (var timer = new System.Windows.Forms.Timer())
using (token.Register(() => tcs.TrySetCanceled(), useSynchronizationContext: true))
{
timer.Interval = delay;
timer.Tick += (s, e) => tcs.TrySetResult(true);
timer.Enabled = true;
await tcs.Task;
timer.Enabled = false;
}
}
I don't think Task.Delay would be suitable for this approach, as it uses Kernel timer objects, which are independent of the message loop and its priorities.
Updated, I found one more option: WH_FOREGROUNDIDLE/ForegroundIdleProc. Looks exactly like what I need.
Updated, I also found that a Win32 timer trick is used by WPF for low-priority Dispatcher operations, i.e. Dispatcher.BeginInvoke(DispatcherPriority.Background, ...):

Well, WH_FOREGROUNDIDLE/ForegroundIdleProc hook is great. It behaves in a very similar way to Application.Idle: the hook gets called when the thread's message queue is empty, and the underlying message loop's GetMessage call is about to enter the blocking wait state.
However, I've overlooked one important thing. As it turns, the host app I'm dealing with has its own timers, and its UI thread is pumping WM_TIMER messages constantly and quite frequently. I could have learnt that if I looked at it with Spy++, in the first place.
For ForegroundIdleProc (and for Application.Idle, for that matter), WM_TIMER is no different from any other message. The hook gets called after each new WM_TIMER has been dispatched and the queue has become empty again. That results in ForegroundIdleProc being called much more often than I really need.
Anyway, despite the alien timer messages, the ForegroundIdleProc callback still indicates there is no more user input messages in the thread's queue (i.e., keyboard and mouse are idle). Thus, I can start my idle work upon it and implement some throttling logic using async/await, to kept the UI responsive. This is how it would be different from my initial timer-based approach.

Related

Cannot cancel durable timer when waiting for external event with timeout

I am using durable functions to wait for external events with timeouts. Even though one of the events is received before the timeout, a TimerFired event is recognised in dfMon when none should be.
The orchestration's logic is as follows:
orchstration will put a message on a queue which is monitored by an external system
this remote system will notify my orchestration via cmdReceived external event if the above queue message was received
then it will trigger a long-running local process
afterwards it will again notify my orchestration via cmdExecuted external event of the completion of this process
I.e. ->
PUT a message on the queue
timer1: wait 10mins for external event cmdReceived, continue if received, else throw
timer2: wait 60mins for external event cmdExecuted, continue if received, else throw
Now the cmdReceived event is received rather quickly, after 2mins or so. The the next timer should wait for a max of 60mins for cmdExecuted to be received. This usually takes about 12mins or so. By then 10mins (from timer1) have elapsed. And a TimerFired event is logged, however no exception is thrown and the orchestration keeps on running. But I do ask myself whether there is still an impact I am not immediately aware of. The existence of the TimerFired event (timer1) I mean.
This is the relevant line of code:
await ctx.WaitForExternalEvent("cmdReceived", TimeSpan.FromMinutes(10));
var success = await ctx.WaitForExternalEvent<bool>("cmdExecuted", TimeSpan.FromMinutes(60));
My first thought was, that maybe I need to explicitly cancel the timer myself. I've read about this here. So then I tried:
var cts = new CancellationTokenSource();
await ctx.WaitForExternalEvent("cmdReceived", TimeSpan.FromMinutes(10), cts.Token);
cts.Cancel();
var cts2 = new CancellationTokenSource();
var success = await ctx.WaitForExternalEvent<bool>("cmdExecuted", TimeSpan.FromMinutes(60), cts2.Token);
cts2.Cancel();
However, this didn't really help. The first timer keeps on firing (though not throwing) after 10mins even after the event for which it was configured has already been received.
See below for a screenshot from dfMon.
Is there anything wrong about this? I find this extra TimerFired event confusing. Does it matter as long as it is (correctly) not throwing an exception?
Cheers
Short answer: no it does not matter. The event is ignored by Durable Task.
The way that durable timers work with the default Storage durability provider is through scheduled queue messages.
So when you call WaitForExternalEvent, it uses CreateTimer under the hood.
When the replay finishes and Durable Task sees that there is a timer that needs to be started, it sends a scheduled message to one of the control queues.
This message will become visible at the time you specified.
Now when your orchestration receives the external event, that causes a replay, and it'll replay over the WaitForExternalEvent call.
Here it sees it has a new event for a received event.
This resolves the Task it is waiting on and your orchestration continues.
The next time it replays the timer event arrives.
But the timer gets ignored by processing the external event first.
(Internally it uses TaskCompletionSource.TrySetException() which won't do anything because SetResult has already been called)
It won't throw the timeout exception.
Regardless that it did nothing, the event did occur so it is recorded.

C# How to make a thread wait for either of two Manual Reset Events?

I have a thread that grabs messages from a concurrent queue and writes them to a network stream. The loop inside the thread looks like this:
while (!cancel.IsCancellationRequested)
{
messageBus.outboundPending.WaitOne();
var message = messageBus.GetFrom(Direction.Outbound);
if (message == null) { continue; }
MessageWriter.WriteMessage(networkStream, message, cancel, OnStreamClose).Wait(cancel);
}
The requirement is that the thread stops if the cancellation token is set. However, since it waits for pending messages in the queue, the thread will stay blocked. How could I "combine" both the cancellation token and the outbound event so that if either of them are set, the thread unblocks?
The only convoluted way that I can think of to make it work is to replace the outboundPending event with a new third event, and start two new threads: one that waits for the outbound event, and another that waits for the cancel event, and have both of them set the third event when they unblock. But that feels really bad.
Try WaitHandle.WaitAny and include the CancellationToken.WaitHandle.
A discussion of a cancellable WaitAll can be found here
Use the WaitOne(TimeSpan) method. It will return true if it was signaled, and false if the timeout was reached.
e.g, if you send TimeSpan.FromSeconds(1) and a second has passed without a signal, the execution will continue and the method will return false. If the signal was given, it will return true.

Scheduled operations in C# with option to FullStop immediately

I need to do some operations on a certain interval (e.g. from 5 to 5 minutes in a loop) but need to be able to fully stop the thing whenever I want (on push of a button).
I was thinking into using a Timer class but events might fire even after the timer is stopped.
How can I have some code running on a timer and still be able to immediately bring everything to a complete stop?
Just so I am properly understood: By complete stop I mean that events stop and I can dispose of objects like the timer itself etc. I am not asking how to avoid having side effects from unexpected events that are fired after the timer is stopped!
Answer to this question depends a lot on a type of your operations.
Best scenario is to run a thread with a loop and listen to abort event.
static AutoResetEvent abort = new AutoResetEvent();
Thread worker = new Thread(WorkerThread);
void MainThread()
{
worker.Start();
Thread.Sleep(30000);
abort.Set();
}
void WorkerThread()
{
while(true)
{
if(abort.WaitOne(5000)) return;
// DO YOUR JOB
}
}
When you call abort.Set() from another thread, this one will exit.
But if your code is long running, you won't be able to exit until job is done.
To exit immediately you will have to abort thread, but this is not too wise because of resource consumption.
Alternatively, if your operation is long running (let's say you are going through long array), you can check "abort" event state from time to time (every iteration of loop, for example) like this abort.WaitOne(0).
The race condition with the timer is unavoidable since, as you say, the callbacks are executed from the thread pool. However, I believe you can safely dispose the timer even while it's still executing the events. An option which might help is if you consider using the System.Threading.Timer instead of System.Timers.Timer, for which you can call Timer.Dispose(WaitHandle) if you need to have a way to know when the timer events have finished executing. This will prevent race conditions for the cases where you also need to dispose of some other resource - a resource that the event consumer function will attempt to use.
As for the "immediate" requirement, the most immediate would probably be something that uses a synchronization primitive of sorts to stop execution. For example consider this:
static System.Timers.Timer timer;
static void Main(string[] args)
{
var cancelSource = new CancellationTokenSource();
timer = new System.Timers.Timer(200);
timer.Elapsed += new SomeTimerConsumer(cancelSource.Token).timer_Elapsed;
timer.Start();
// Let it run for a while
Thread.Sleep(5000);
// Stop "immediately"
cancelSource.Cancel(); // Tell running events to finish ASAP
lock (timer)
timer.Dispose();
}
class SomeTimerConsumer
{
private CancellationToken cancelTimer;
public SomeTimerConsumer(CancellationToken cancelTimer)
{
this.cancelTimer = cancelTimer;
}
public void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
lock (timer)
{
// Do some potentially long operation, that respects cancellation requests
if (cancelTimer.IsCancellationRequested)
return;
// More stuff here
}
}
}
This is a toy example, but it illustrates my point. The 3 lines that do the "stop immediately" have the following features:
By the time the Dispose call returns, none of the // More stuff here code will ever execute again.
None of the // More stuff here code can execute while the timer is being disposed, because of the lock.
The previous 2 features require the lock, but they prevent the timer from stopping "immediately" because on entering the lock it needs to wait for all timer events calls to finish if they have started. For this reason I added in the cancellation as the fastest way to abort the currently executing events while still guaranteeing that they won't be executing during timer dispose.
Note: if you need multiple timer events to execute simultaneously, consider using a ReaderWriterLockSlim instead of a monitor.
I'd consider one of these two options:
Put a safety check in the events that you need to execute. Something like a database flag. So even if the Timer fails to stop the event will bail out when the safety check fails.
Use something like Quartz.Net for scheduling. This is really heavy handed but it'll do what you want.

Replace infinite thread loop (message pump) with Tasks

In my application I have to listen on multiple different queues and deserialize/dispatch incoming messages received on queues.
Actually, what I am doing to achieve this is that each QueueConnector object creates a new thread on construction, which executes a infinite loop with a blocking call to queue.Receive() to receive next message in queue as exposed by the code below :
// Instantiate message pump thread
msmqPumpThread = new Thread(() => while (true)
{
// Blocking call (infinite timeout)
// Wait for a new message to come in queue and get it
var message = queue.Receive();
// Deserialize/Dispatch message
DeserializeAndDispatchMessage(message);
}).Start();
I'd like to know if this "message pump" can be replaced using Task(s) instead of going through an infinite loop on a new Thread.
I made a task already for the Message receiving part (see below) but I don't really see how to use it for a message pump (Can I recall the same task on completion over and over again, with continuations, replacing infinite loop in separate thread as in the code above ?)
Task<Message> GetMessageFromQueueAsync()
{
var tcs = new TaskCompletionSource<Message>();
ReceiveCompletedEventHandler receiveCompletedHandler = null;
receiveCompletedHandler = (s, e) =>
{
queue.ReceiveCompleted -= receiveCompletedHandler;
tcs.SetResult(e.Message);
};
queue.BeginReceive();
return tcs.Task;
}
Will I gain anything by using Tasks instead of an infinite loop in a separate thread (with a blocking call => blocking thread) in this context ? And if yes, how to do it properly ?
Please note that this application don't have a lot of QueueConnector objects, and won't have (maybe 10 connectors MAX), meaning ten Threads max through the first solution, so memory footprint / performance starting threads is not an issue here. I was rather thinking about scheduling performance / CPU usage. Will there be any difference ?
You will generally have more overhead and less throughput with async code when the count of threads is low. Nonblocking code is most useful when the number of threads is very high causing a) lots of wasted memory due to stacks and b) context switches. It has noticable overhead though because of more allocation, more indirection and more user-kernel-transitions.
For low thread counts (< 100) you probably shouldn't worry. Try to focus on writing maintainable, bug-resistant and simple code. Use threads.

C# waiting for input from another thread using AutoResetEvent

I spent some time searching for an answer to this and found plenty of helpful information in other threads. I believe I've written the code in a way that works, but I am not happy with the outcome.
I designed a piece of hardware that I am communicating with via C#. The hardware connects via USB and runs initialization routines after enumerating with the OS. At that point, it simply waits for the C# program to start sending commands. In my C# code, the user must press a "Connect" button, which sends a command and the required payload to let the hardware know it should continue running. The hardware then sends a command back as an ACK. The problem is that my C# program must wait to receive the ACK, but the GUI is totally frozen until the hardware responds as I don't know how to partition it out to another thread that can block freely. If the hardware responds immediately, then it works fine, but if it can't connect, then the program stays frozen indefinitely.
With that said, I know a few things need to happen, but I'm not sure how to implement them. First and foremost, I don't think sitting in a loop waiting on a boolean is the right way to go, but using AutoResetEvent doesn't really seem to be much better. There has to be a better way involving timers, more threads, or something similar.
I am using the DataReceived event with the serialPort object as follows:
private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
byte cmd = (byte)serialPort1.ReadByte();
if (cmd == (byte)Commands.USB_UART_CMD_MCU_CONNECT)
MCU_Connect_Received.Set();
}
In the buttonClick function ("main" thread), the program stops while it waits for the ACK:
//Send the command to signal a connection
Send_Connection_Packet((byte)Commands.USB_UART_CMD_PC_CONNECT);
textBox1.AppendText("-I- Attempting to contact hardware...");
MCU_Connect_Received.WaitOne();
textBox1.AppendText("Success!" + Environment.NewLine);
Ideally, I'd like to know if a timeout expired so I can print "Failed!" instead of "Success!". Not having a timeout also means it will sit there forever, as I mentioned above, until I kill the process. It's possible that it won't find any hardware, but if it does, it should respond in < 1 second, so a timeout of 2 seconds would be more than enough. I tried using Thread.Sleep, but that froze the GUI as well.
I recommend you use the Task class. You can use a TaskCompletionSource to complete the task when the operation completes.
Using the new async support, your code then becomes:
textBox1.AppendText("-I- Attempting to contact hardware...");
await Send_Connection_Packet((byte)Commands.USB_UART_CMD_PC_CONNECT);
textBox1.AppendText("Success!" + Environment.NewLine);
If you don't want to use the Async CTP, then you can call Task.ContinueWith and pass TaskScheduler.FromCurrentSynchronizationContext to schedule the textBox1.AppendText("Success!") line to run on the UI thread.
The async support also includes timers (TaskEx.Delay) and combinators (TaskEx.WhenAny), so you can easily check for timeouts:
textBox1.AppendText("-I- Attempting to contact hardware...");
var commTask = Send_Connection_Packet((byte)Commands.USB_UART_CMD_PC_CONNECT);
var timeoutTask = TaskEx.Delay(1000);
var completedTask = TaskEx.WhenAny(commTask, timeoutTask);
if (completedTask == commTask)
textBox1.AppendText("Success!" + Environment.NewLine);
else
textBox1.AppendText("Timeout :(" + Environment.NewLine);
The issue with the GUI freezing is because all the callbacks for GUI events occur in the thread that's running the GUI. If you don't want the GUI to freeze you need to spawn a new thread.
For implementing the timeout, you can do a timed wait on an event handle and then check the return value for true or false to determine if the call was successful or if it timed out.
To enable timeouts use another overload of WaitOne():
bool succeeded = MCU_Connect_Received.WaitOne(timeOutInMilliseconds, false);
if (succeeded)
{
textBox1.AppendText("Success!" + Environment.NewLine);
}
else
{
textBox1.AppendText("Failed!" + Environment.NewLine);
}
Consider moving communication-related code in a separate class to encapsulate the communication protocol. This way the code will be easier to maintain and you will able to implement all Task/background worker ideas the other people suggested.
If you want the GUI to remain responsive, you should run things in a background thread. A BackgroundWorker does this nicely. I'd stick with the resetevent over a busy wait construction. You can use a timer to trigger the resetevent after a timeout period

Categories