Using Dispatcher correctly in event to update UI - c#

I'm using dispatchers to update a bound collection from an event. I just ran into a nasty issue where I had two different dispatchers in the same event and it wasn't working. Using the debugger it was completely skipping over the code in the first dispatcher. Putting the entire event in a single dispatcher fixed it. I assume it's because of how the compiler handles it, can anyone confirm this - only one dispatcher per event, at least when dealing with the same elements?
Here is the code, when it gets to the await after (line == 0), it exits the function completely. Later, when line !=0 it runs the "Old style menu" fine. If I put all of the code in a single dispatcher, everything works fine.
private async void ProcessNLS(string parameters) // NET/USB List Info
{
if (parameters.Substring(0, 1) == "A" || (parameters.Substring(0, 1) == "U")) // ASCII x08/2010 Only
{
int line = Convert.ToInt32(parameters.Substring(1, 1));
string text = parameters.Substring(3);
// New Menu, Clear Old - Use Last Received/Holding Menu: See NLT bug
if (line == 0)
{
await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
State.Menu.ServiceType = State.holdingMenu.ServiceType;
...
State.Menu.Items.Clear();
});
OnMenuTitleInfoChanged(new MenuTitleInfoChangedArgs(State.Menu));
// Replace Network Top with custom menu
if (State.Menu.LayerInfo == LayerTypes.NetworkTop)
{
await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
State.Menu.Items.Clear();
});
...
}
// Get 1st Advanced Menu
if (Device.SupportsAdvancedMenus & State.Menu.LayerInfo != LayerTypes.NetworkTop)
{
...
}
}
// Old style menu
if (!Device.SupportsAdvancedMenus && State.Menu.LayerInfo != LayerTypes.NetworkTop)
{
NetworkMenuItem menuItem = new NetworkMenuItem(line, text);
await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
State.Menu.Items.Add(menuItem);
});
OnMenuLoading(new MenuLoadingArgs(menuItem));
}
}
// C - Track Cursor
if (parameters.Substring(0,1) == "C")
{
if (parameters.Substring(1, 1)== "-")
{
// No Cursor
// Sent when entering player screen
await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
...
State.Menu.Items.Clear();
OnMenuTitleInfoChanged(new MenuTitleInfoChangedArgs(State.Menu));
}
}
});
}
Like this it would just jump over the dispatcher for no apparent reason. If I put the entire thing in a single dispatcher it works fine.
A second question, if I have another event with a dispatcher, something like this:
foreach (xxx)
{
if (xxx == yyy)
{
await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, async () =>
{
State.Menu.Items.Add(menuItem);
});
}
}
Would it be preferable to instead wrap the entire foreach loop in a dispatcher rather then calling it when needed each iteration?
Since my original question has changed I've made a new post with more specifics and another possible solution by just wrapping the original socket listener task in a dispatcher
Possible solution to issue with multiple UI dispatchers in the same method?
*** Update:
I think Raymond is on the right track, though adding Task didn't fix it, I noticed although it starts processing line "0" of the menu, before it sets up the new menu it tries to process the next line "1" command which is ignored because it doesn't have the right menu state yet, it still hasn't been set by the previous command yet.
I'm not sure how to fix it, it seems like I have to do an await at a lower level so be sure sure it full finishes one command before starting the next (and not sure why putting the whole ProcessNLS in UI dispatcher works), it's a little complicated since I go through multiple levels but here is the flow:
socket = new StreamSocket();
try
{
await socket.ConnectAsync(new HostName(HostName), Port);
OnConnect(new EventArgs());
await Task.Factory.StartNew(WaitForMessage);
}
catch (Exception ex)
{
OnConnectionFail(new EventArgs());
}
Goes to:
private async void WaitForMessage()
{
...
foreach (var message in messages)
{
if (string.IsNullOrWhiteSpace(message))
continue;
ProcessMessage(message);
}
}
Goes to
private void ProcessMessage(string message, string optionalFlags = "")
{
...
case "NLS": // NET/USB List Info
ProcessNLS(parameters);
break;
}
to finally
private async void ProcessNLS(string parameters) // NET/USB List Info
My alternate solution is to put to ProcessMessage call under WaitForMessage in a UI dispatcher
*** Update #2
I think this may be working, here is the updated flow, have to await multiple steps, use task instead of void
private async void WaitForMessage()
{
...
foreach (var message in messages)
{
if (string.IsNullOrWhiteSpace(message))
continue;
await ProcessMessage(message);
}
}
}
catch (Exception ex)
{
Debug.WriteLine("WaitForMessage Error: " + ex.Message);
OnDisconnect(new EventArgs());
}
}
to
private async Task ProcessMessage(string message, string optionalFlags = "")
{
...
case "NLS": // NET/USB List Info
await ProcessNLS(parameters);
break;
}
to
private async Task ProcessNLS(string parameters) // NET/USB List Info

The problem is here:
private async void ProcessNLS(...)
^^^^^^^^^^
You declared an async void function, which means "When the first await happens, return from the function immediately, and let the rest of the work run asynchronously." If you want the caller to be able to await on completion of your function, change the signature to private async Task ProcessNLS(...).

Related

The event stops halfway

I am executing an asynchronous anonymous method that is called by an event, but it terminates halfway through without executing half the code.
Method, that called when an event called.
private void OnBlockGenerationTime()
{
Task.Run(async () =>
{
await Task.Delay(10);
if (!ChainMutex.WaitOne(3000))
throw new TimeoutException("Cannot access to blockchain, mutex was held too long.");
var winnerTrx = PoS.GetWinner(Blockchain.LatestBlock.ID);
ChainMutex.ReleaseMutex();
if (winnerTrx == null)
return;
var winner = PoolsSet.TransactionPool.GetTxOut(winnerTrx.Trx.Inputs[0]).Address;
if (winner == CurrentAccount.GetAddress())
{
var (block, reward) = Blockchain.CreateBlock(CurrentAccount.GetPrivateKey()); //here task terminating.
CommonLog.Log(LogElementType.OK, $"Our stake won. A new block with ID {block.ID} was created. {reward} AWT were collected.");
P2P.BroadcastLatestBlock();
}
});
}
Method with infinte task, that calles event:
private void RunNewBlockListening()
{
Task.Run(async () =>
{
while (true)
{
while (GetRemainingToNewBlock() != 0) { await Task.Delay(100); }
OnNewBlockGeneration?.Invoke();
await Task.Delay(1000);
}
});
}
I know that asynchronous methods are executed in different ways, but the marked code is never executed when debagged.
Thank you all for your help, those who are looking for an answer to catching exceptions in anonymous functions, just click on the "Common Language Runtime Exceptions" checkbox in the "Exception parameters" tab (Debugging -> Windows -> Exception Parameters).
That's all.

performance issues with WPF

I am working with a dnp3 nuget package and I want to implement it in a WPF, and I achieve it by referring to this example https://github.com/stepfunc/dnp3/blob/master/ffi/bindings/dotnet/examples/master/Program.cs
I managed to implement it by an MVVM method where it dynamically shows the messages it receives (in the gif it shows an error because it did not create another program that will connect but the important thing is that it is being updated).
but I created another much simpler project to do the demonstration here on github , in my project create a class called protocol and paste all the master example eliminating the main function and changing the private functions for public functions, then inside my MainWindow.xaml.cs start the code
{
public MainWindow()
{
InitializeComponent();
// ANCHOR: logging_init
// Initialize logging with the default configuration
// This may only be called once during program initialization
Logging.Configure(
new LoggingConfig(),
new Protocolo.ConsoleLogger()
);
// ANCHOR_END: logging_init
// ANCHOR: runtime_init
var runtime = new Runtime(new RuntimeConfig { NumCoreThreads = 4 });
// ANCHOR_END: runtime_init
// ANCHOR: create_master_channel
var channel = MasterChannel.CreateTcpChannel(
runtime,
LinkErrorMode.Close,
Protocolo. GetMasterChannelConfig(),
new EndpointList("127.0.0.1:20000"),
new ConnectStrategy(),
new Protocolo.TestListener()
);
// ANCHOR_END: create_master_channel
Task.Run(() =>
{
try
{
Protocolo.RunChannel(channel).GetAwaiter().GetResult();
}
finally
{
// ANCHOR: runtime_shutdown
runtime.Shutdown();
// ANCHOR_END: runtime_shutdown
}
}
);
}
}
I did performance profiles and RunChannel is what they demand a lot from the CPU
public static async Task RunChannel(MasterChannel channel)
{
// ANCHOR: association_create
var association = channel.AddAssociation(
1024,
GetAssociationConfig(),
new TestReadHandler(),
new TestAssocationHandler()
);
// ANCHOR_END: association_create
// ANCHOR: add_poll
var poll = channel.AddPoll(association, Request.ClassRequest(false, true, true, true), TimeSpan.FromSeconds(5));
// ANCHOR_END: add_poll
// start communications
channel.Enable();
while (true)
{
//Here there was a switch that read the commands that were entered into the console but it is unnecessary, with the empty while it continues to update
}
}
I don't know why but without the While the received messages are not updated, (these messages arrive in the Logger) I have to keep this function always alive but I don't know how to do it without consuming so much CPU
to see the messages in the output you have to change Console.WriteLine to Debug.WriteLine
class ConsoleLogger : ILogger
{
public void OnMessage(LogLevel level, string message)
{
Console.Write($"{message}");
//this is inside the master example in the github link
}
}
As commented before (answering about "performance issue"):
Your empty while loop running without any pause or job. You need to fill loop with some job or simple pause (Thread.Sleep(10)/await Task.Delay(10)).
Your RunChannel method have no any await, so you should get CS1998 warning "This async method lacks 'await'" and, obviously, put it into your while loop.
On DNP3 Github example, there is await GetInputAsync() inside while loop, which waits for user input with Console.ReadLine() and returns inputed string into switch statement.
So:
public MainWindow()
{
// InitializeComponent() and other stuff...
Task.Run(async () => // Make it async
{
try
{
// You really didn't want GetAwaiter().GetResult().
await Protocolo.RunChannel(channel);
}
finally
{
runtime.Shutdown();
}
});
}
public class Protocolo
{
public static async Task RunChannel(MasterChannel channel)
{
// Associations and polls stuff...
while (true)
{
await Task.Delay(10); // Set some delay or...
await SomeJob(); // ...or do some job or ...
switch (await GetInputAsync()) // ...or take github's example
{
case "x":
return;
default:
Console.WriteLine("Unknown command");
break;
}
}
}
public static Task SomeJob()
{
return Task.Run(() =>
{
for (int i = 0; i < 5; i++)
{
Thread.Sleep(200); // 200 x 5 = Total task for 1 second
}
});
}
public static Task<string> GetInputAsync()
{
return Task.Run(() => Console.ReadLine());
}
}

Why is Thread.Sleep() used in following context and how to avoid it?

I'm going through following method which is sending messages over Http.
private static void HTTPProcessQueue()
{
while (true)
{
try
{
Thread.Sleep(10000);
Utils.LogDebug("Msg Queue Check");
while (msgQueue.Count > 0)
{
QueueItem queueItem;
lock (msgQueue)
{
queueItem = msgQueue.Dequeue();
}
if (queueItem != null)
if(!HTTPTransmitEmailItem(queueItem.username, queueItem.filename))
Thread.Sleep(5000);
}
}
catch (Exception ex)
{
}
}
}
In the code above, why are Thread.Sleep(10000) and Thread.Sleep(5000) used in lines 7 and 18?
Also, why is there a while(true) in line 3?
As you requested, here is a slightly better way of doing it:
private static System.Collections.Concurrent.BlockingCollection<MsgType> msgQueue = new System.Collections.Concurrent.BlockingCollection<MsgType>();
private static void AddQueueItems() // simulate adding items to the queue
{
msgQueue.Add(new MsgType());
msgQueue.Add(new MsgType());
msgQueue.Add(new MsgType());
msgQueue.Add(new MsgType());
// when adding is done, or the program is shutting down
msgQueue.CompleteAdding();
}
private static void HTTPProcessQueue()
{
foreach (var queueItem in msgQueue.GetConsumingEnumerable())
{
if (queueItem != null)
{
if (!HTTPTransmitEmailItem(queueItem.username, queueItem.filename))
{
Thread.Sleep(5000);
}
}
}
}
I'd recommending using the async/await pattern with HTTPTransmitEmailItem, and then you can use await Task.Delay(...) instead of Thread.Sleep(...). I've also not included any error checking in this code.
This would then look more like:
private static async Task HTTPProcessQueue()
{
foreach (var queueItem in msgQueue.GetConsumingEnumerable())
{
if (queueItem != null)
{
if (!(await HTTPTransmitEmailItemAsync(queueItem.username, queueItem.filename)))
{
await Task.Delay(5000);
}
}
}
}
But you would have to make a HttpTransmitEmailItemAsync method. Also note that the GetConsumingEnumerable(...) method has an overload which takes a CancellationToken, so you could use this to gain more control over when to end the queue process. You can learn about async/await here.
The Thread.Sleep(10000) is used on line 7 to let the system pause / wait for 10 seconds before it starts the function Utils.LogDebug("Msg Queue Check"); to log the debug information with message "Msg Queue Check". and i believe the Thread.Sleep(5000) is added at the end of loop to create a delay or to wait for 5 seconds before process the next loop.
while(true) is usually used for infinite loop. all method inside this loop will run in loop in infinite time.

Is Looping inside a Task Recommended?

Is Looping inside a task really recommended?
example code:
public void doTask(){
Task.Factory.StartNew(() => {
do{
// do tasks here.... call webservice
}while(true till cancelled)
});
}
any answers would be great! :)
because it is a case for my webservice calling right now, and the memory consumption goes out of control.
So may I ask, is looping inside a task really good or not recommended at all?
As Requested by SLC, heres the code:
CancellationTokenSource tokenSrc;
Task myTask;
private void btnStart_Click(object sender, EventArgs e)
{
isPressed = !isPressed;
if(isPressed)
{
tokenSrc = new CancellationTokenSource();
myTask = Task.Factory.StartNew(() =>
{
do{
checkMatches(tokenSrc.Token);
}while(tokenSrc.IsCancellationRequested != true);
}, tokenSrc.Token);
}
else {
try{
tokenSrc.Cancel();
// Log to notepad
}
catch(Exception err){
// Log to notepad
}
finally {
if(myTask.IsCanceled || myTask.IsCompleted || myTask.isFaulted) {
myTask.Dispose();
}
}
}
}
private void checkMatches(CancellationTokenSource token)
{
try
{
if(!token.IsCancellationRequested)
{
//Create Endpoint...
//Bypass ServCertValidation for test purposes
ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(delegate {return true;});
using(WebServiceAsmx.SoapClient client = new....)
{
client.CheckResp response = client.chkMatch();
// if's here for the response then put to logs
}
}
}
catch(Exception err)
{
// err.toLogs
}
}
It's perfectly fine to do this, especially if your task runs constantly, for example picking up a message queue.
while (not shutting down)
get next email to send
if exists next email to send
send
else
wait for 10 seconds
wend
Ensure that you have a way to get out if you need to cancel it, like you've done with a flag, and you should be fine.
Regarding webservices:
You should have no problem calling the webservice repeatedly, nor should it cause any memory spikes. However, you should make sure your initialisation code is not inside the loop:
BAD
while (notShuttingDown)
make a new connection
initialise
make a call to the service()
wend
GOOD
make a new connection
initialise
while (notShuttingDown)
make a call to the service
wend
Depending on your webservice it might be more optimal to create a batch operation, for example if your service is HTTP then hitting it repeatedly involves a lot of overhead. A persistent TCP connection might be better because it could be creating and destroying a lot of objects to make the calls.
For example
slow, lots of overhead:
myRecords = { cat, dog, mouse }
foreach record in myRecords
webservice check record
endforeach
faster:
myRecords = { cat, dog, mouse }
webservice check [myRecords] // array of records is passed instead of one by one
Debugging: The most likely risk is that somehow the task is not being disposed correctly - can you add this to your method to debug?
myTask = Task.Factory.StartNew(() =>
{
Console.Writeline("Task Started");
do{
checkMatches(tokenSrc.Token);
Thread.Sleep(10); // Some pause to stop your code from going as fast as it possibly can and putting your CPU usage to 100% (or 100/number of cores%)
}while(tokenSrc.IsCancellationRequested != true);
Console.Writeline("Task Stopped");
}
You might have to change that so it writes to a file or similar depending on if you have a console.
Then run it and make sure that only 1 task is being created.

async eventhandler executed multiple times

I have this eventhandler, that can get executed multiple times. When I let it finish the execution, everything works fine (typing only one character and wait until the result is computed).
But when I type normally, a deadlock occurs. At least I think it is a deadlock.
private async void tbInput_TextChanged(object sender, TextChangedEventArgs e)
{
resultStackPanel.Children.Clear();
List<Task<UIElement>> tasks = new List<Task<UIElement>>();
if (tbInput.Text != "")
{
foreach (IModule mod in Modules)
{
if (mod.IsApplicable(tbInput.Text))
tasks.Add(mod.CalculateOutcome(tbInput.Text));
}
while (tasks.Count > 0)
{
await Task.WhenAny(tasks);
foreach (Task<UIElement> resultTask in tasks)
{
if (resultTask.Status == TaskStatus.RanToCompletion)
{
if (resultTask.Result != null)
{
resultStackPanel.Children.Add(resultTask.Result);
}
tasks.Remove(resultTask);
break;
}
}
}
}
}
I am pretty sure it is because of this line and that I should cancel all tasks, but I dont know how, since CancellationToken is useless because the libraries that perform the heavy work dont support it:
await Task.WhenAny(tasks);
I can see a few problems with your code as-is. For one, you'll get an infinite loop if any task does not complete successfully. For another, your existing tasks will still run to completion and attempt to update your UI.
Since your libraries don't support CancellationToken, you can't actually cancel the operations (which is bad). But you can at least pretend to cancel them by allowing them to run to completion and then ignoring the result. You can use a technique I call asynchronous callback contexts for this.
It's easier to split logic like this off into another method, instead of using a continuation; something like this:
private object _callbackContext;
private async void tbInput_TextChanged(object sender, TextChangedEventArgs e)
{
_callbackContext = new object();
resultStackPanel.Children.Clear();
if (tbInput.Text == "")
return;
Modules.Where(mod => mod.IsApplicable(tbInput.Text))
.Select(mod => ApplyModuleAsync(mod));
}
private async Task ApplyModuleAsync(IModule module)
{
var myContext = _callbackContext;
var element = await module.CalculateOutcome(tbInput.Text);
if (myContext != _callbackContext || element == null)
return;
resultStackPanel.Children.Add(element);
}
You can just add a continuation to the async method you're calling and then just asynchronously wait for all of them to complete with Task.WhenAll:
foreach (IModule mod in Modules)
{
if (mod.IsApplicable(tbInput.Text))
{
tasks.Add(mod.CalculateOutcome(tbInput.Text).ContinueWith(resultTask =>
{
if (resultTask.Result != null)
{
resultStackPanel.Children.Add(resultTask.Result);
}
}, TaskContinuationOptions.OnlyOnRanToCompletion));
}
}
await Task.WhenAll(tasks.ToArray());

Categories

Resources