BackgroundWorker.RunWorkerCompleted event in WPF - backgroundworker

There is a scenario in which a user terminates the application, while it is still processing data via BackgroundWorker.
I would like to send cancel or terminate command to this method. I tried calling CancelAsync() method, but it obviously didn't work the way I expected and the worker still continued processing.
What is a good way to signal the BackgroundWorker, and especially its RunWorkerCompleted method to stop processing?
Do I have to use state variables?

This is the code executed when you call CancelAsync() on a BackgroundWorker
public void CancelAsync()
{
if (!this.WorkerSupportsCancellation)
{
throw new InvalidOperationException(SR.GetString
("BackgroundWorker_WorkerDoesntSupportCancellation"));
}
this.cancellationPending = true;
}
As you can see, they set the internal cancellationPending variable to true after checking the value of WorkerSupportsCancellation.
So you need to set WorkerSupportsCancellation = true;, when you exit from your app call backGroundWorkerInstance.CancelAsync() and inside the DoWork or RunWorkerCompleted test the CancellationPending. If it's true stop your process.

Related

Cancelling a LoadAsync operation after a timeout period and recalling LoadAsync afterwards throws exception

I am working with SerialDevice on C++/winrt and need to listen for data coming over the port. I can successfully work with SerialDevice when data is streaming over the port but if nothing is read the DataReader.LoadAsync() function hangs even though I set timeouts through SerialDevice.ReadTimeout() and SerialDevice.WriteTimeout(). So to cancel the operation I am using IAsyncOperation's wait_for() operation which times out after a provided interval and I call IAsyncOperation's Cancel() and Close(). The problem is I can no longer make another call to DataReader.LoadAsync() without getting a take_ownership_from_abi exception. How can I properly cancel a DataReader.LoadAsync() call to allow subsequent calls to LoadAsync() on the same object?
To work around this, I tried setting the timeouts of SerialDevice but it didn't affect the DataRead.LoadAsync() calls. I also tried using create_task with a cancellation token which also didn't allow for an additional call to LoadAsync(). It took a lot of searching to find this article by Kenny Kerr:
https://kennykerr.ca/2019/06/10/cppwinrt-async-timeouts-made-easy/
where he describes the use of the IAsyncOperation's wait_for function.
Here is the initialization of the SerialDevice and DataReader:
DeviceInformation deviceInfo = devices.GetAt(0);
m_serialDevice = SerialDevice::FromIdAsync(deviceInfo.Id()).get();
m_serialDevice.BaudRate(nBaudRate);
m_serialDevice.DataBits(8);
m_serialDevice.StopBits(SerialStopBitCount::One);
m_serialDevice.Parity(SerialParity::None);
m_serialDevice.ReadTimeout(m_ts);
m_serialDevice.WriteTimeout(m_ts);
m_dataWriter = DataWriter(m_serialDevice.OutputStream());
m_dataReader = DataReader(m_serialDevice.InputStream());
Here is the LoadAsync call:
AsyncStatus iainfo;
auto async = m_dataReader.LoadAsync(STREAM_SIZE);
try {
auto iainfo = async.wait_for(m_ts);
}
catch (...) {};
if (iainfo != AsyncStatus::Completed)
{
async.Cancel();
async.Close();
return 0;
}
else
{
nBytesRead = async.get();
async.Close();
}
So in the case that the AsyncStatus is not Completed, the IAsyncOperation Cancel() and Close() are called which according to the documentation should cancel the Async call but now on subsequent LoadAsync calls I get a take_ownership_from_abi exception.
Anyone have a clue what I'm doing wrong? Why do the SerialDevice timeouts not work in the first place? Is there a better way to cancel the Async call that would allow for further calls without re-initializing DataReader? Generally, it feels like there is very little activity in the C++/winrt space and the documentation is severely lacking (didn't even find the wait_for method until about a day of trying other stuff and randomly searching for clues through different posts) - is there something I'm missing or is this really the case?
Thanks!
Cause: When the wait time is over, the async object is in the AsyncStatus::Started state. It means that the async object is still running.
Solution: When you use close() method, you could use Sleep(m_nTO) let asynchronous operation have enough time to close. Refer the following code.
if (iainfo != AsyncStatus::Completed)
{
m_nReadCount++;
//Sleep(m_nTO);
async.Cancel();
async.Close();
Sleep(m_nTO);
return 0;
}

Should accept() be used only at the end of a slot?

I see the accept() somewhat similar to a return, so I've been putting it a the end of my slots with no code afterwards. That is, the accept() "finishes" the execution of the dialog.
Nevertheless, I came across the need to close a dialog and open a new one from a slot in the first one. Therefore, what I thought was moving the accept() to the beginning of the slot and initializing the second dialog after it. Something like the following:
void FirstDialog:slotFirstDialog()
{
accept();
// Setup second dialog arguments
// ...
SecondDialog *sd = new SecondDialog();
sd->exec();
}
Is this use of accept() valid? Is it good practice?
I'd avoid it. Calling accept() can trigger a delayed deletion of FirstDialog (say, if it has the Qt::WA_DeleteOnClose flag set)1; in that case, it would be deleted in one of the first events dispatched by the nested event loop (sd->exec()), which would lead to go on executing code in a method of an instance that has been deleted. This is just a sample problem on the top of my head, I'm sure others can be found.
I'd probably just hide the dialog before calling exec() on the other, and call accept() after the end of the nested event loop.
void FirstDialog:slotFirstDialog()
{
// Setup second dialog arguments
// ...
SecondDialog *sd = new SecondDialog();
hide();
sd->exec();
accept();
// NB are we leaking sd?
}
By the way:
SecondDialog *sd = new SecondDialog();
sd->exec();
here you are allocating on the heap a dialog without a parent, so either you set the Qt::WA_DeleteOnClose or explicitly call this->deleteLater() inside its code, or you are leaking the dialog instance.
Notes:
and it is explicitly remarked in the documentation
As with QWidget::close(), done() deletes the dialog if the Qt::WA_DeleteOnClose flag is set.
QDialog::accept calls QDialog::done with a dialog code Accepted. Here is how QDialog::done looks like:
void QDialog::done(int r)
{
Q_D(QDialog);
setResult(r);
hide();
d->close_helper(QWidgetPrivate::CloseNoEvent);
d->resetModalitySetByOpen();
emit finished(r);
if (r == Accepted)
emit accepted();
else if (r == Rejected)
emit rejected();
}
which, according to the documentation:
Hides the modal dialog and sets the result code to Accepted.
With this in mind, I think this is not a question of a good practice, but of what your application logic requires.

PNaCl: Handle another message while already in 'HandleMessage' function?

I'm using PNaCl and I'm in a situation where first I receive a message that is handled in the 'HandleMessage' function as the normal way, but then in the current HandleMessage execution, I need to wait for a user input that would come from an other message in order to complete the execution.
I'm wondering if this is possible to do that (handling a message while already waiting in the 'HandleMessage' function) ? And if so, can someone give me a trick ?
Thanks !
HandleMessage is currently called on one thread, the main thread. So you cannot receive a message while you are handling another message.
We typically suggest you spawn a new thread to do your work, and leave the main thread to handle messages, and queue them for the new thread to handle. Take a look at the nacl_io_demo example in the SDK for an example of this technique (found in examples/demo/nacl_io).
Another solution is to use a state machine; i.e. keep track of your current state in a variable instead of on the stack.
For example:
enum State {
STATE_INIT,
STATE_WAITING_FOR_INPUT,
STATE_DO_OTHER_STUFF,
};
State state_;
virtual void HandleMessage(const pp::Var& var_message) {
switch (state_) {
case STATE_INIT:
if (var_message.AsString() == "first_message") {
state_ = STATE_WAITING_FOR_INPUT;
// Do some work before you need the user input ...
}
break;
case STATE_WAITING_FOR_INPUT:
if (var_message.AsString() == "user_input") {
// Do more work, now that we've received input from the user...
state_ = STATE_DO_OTHER_STUFF;
}
break;
}
}

Nested mvvm-light Messenger sends while using the Dispatcher + multithreaded = Deadlock

Here is basically what is happening....
Class A (Main thread) sends an MVVM message
This message is received, and in the course of processing, Class B is constructed and kicks off a background task.
This background sends an seperate MVVM message.
Class C has registered for this message and does an invoke on the dispatcher to attempt to update the UI.
At this point the main thread is still executing the original Send command and the threads are deadlocked (I can pause the debugger and see they are both waiting).
Other Notes
If I add a sleep in the background thread for one second (allowing the main thread's Send method to complete) it works fine.
This only happens if there is a nested MVVM message sent on another thread which invokes on the dispatcher.
Commenting out the dispatcher call...fine.
Not using an MVVM message to invoke the dispatcher...fine.
Can anyone explain what is going on?
I'll take a stab at this...
You can take a look at the MVVM-Light source code on its CodePlex site. I'm going to paste in the relevant method here (slightly annotated for the sake of this post):
private void SendToTargetOrType<TMessage>(TMessage message, Type messageTargetType, object token)
{
var messageType = typeof(TMessage);
if (_recipientsOfSubclassesAction != null)
{
// Clone to protect from people registering in a "receive message" method
// Correction Messaging BL0008.002
var listClone =
_recipientsOfSubclassesAction.Keys.Take(_recipientsOfSubclassesAction.Count()).ToList();
foreach (var type in listClone)
{
List<WeakActionAndToken> list = null;
if (messageType == type
|| messageType.IsSubclassOf(type)
|| type.IsAssignableFrom(messageType))
{
lock (_recipientsOfSubclassesAction)
{
list = _recipientsOfSubclassesAction[type].Take(_recipientsOfSubclassesAction[type].Count()).ToList();
}
}
// Class A probably sends a message here from the UI thread
SendToList(message, list, messageTargetType, token);
}
}
if (_recipientsStrictAction != null)
{
// Class B grabs this lock on the background thread.
// Class A continues processing on the UI thread and arrives here.
// An attempt is made to grab the lock on the UI thread but it is
// blocked by the background thread & Class B which in turn is waiting
// on the UI thread. And here you have yourself a deadlock
lock (_recipientsStrictAction)
{
if (_recipientsStrictAction.ContainsKey(messageType))
{
var list = _recipientsStrictAction[messageType]
.Take(_recipientsStrictAction[messageType].Count())
.ToList();
// Class B sends its message here.
// Class C receives the message and does an Invoke on the UI thread
SendToList(message, list, messageTargetType, token);
}
}
}
RequestCleanup();
}
Class A probably sends a message on the UI thread picked up by 'subclass recipients'.
Class B is a recipient that picks up this message and kicks off your background task.
Your background task then sends a message that has a 'strict action recipient'.
Class B grabs the '_recipientsStrictAction' lock on the background thread.
Class B sends the message to class C, which does an invoke on the UI thread.
This invoke blocks because the UI thread is still executing the first message.
UI thread execution continues on and then tries to grab the '_recipientsStrictAction' lock on the UI thread. Unfortunately, your background thread (which is waiting on the UI thread) already has the lock. You are now deadlocked :(
Might want to consider doing an InvokeAsync in Class C rather than an Invoke. I think you could probably avoid the issue that way.
Makes me wonder why MVVM light is sending the message 'inside' the lock. Seems like a not-so-cool sort of thing to do. After typing all this up, I went looking around the CodePlex site, looks like this is issue has been documented:
http://mvvmlight.codeplex.com/workitem/7581

How does ASP.NET AJAX work when retrieving values from the server?

If I want to call a server function from JavaScript to retrieve a name of a person from a database (just as an example)... and I went...
name = myServices.getName(userId);
If I have a script manager with a service reference to a .asmx file that has the web method getName( int userId ) {} then this function should be called properly and would, eventually, return the name for that userId.
Unfortunately, I want to do...
name = myServices.getName(userId);
alert(name);
however, when doing ASP.NET AJAX, it would call the web method and continue executing before waiting for a response from the server (which I understand is the point of AJAX, to stop the browser from freezing while waiting for data)
I need to get the name back from the server before I can continue executing... How can I approach this to fix this issue?
There is a method you can add as a parameter to the service method that will call the method on success where you can do other stuff.
For example:
function test() {
PageMethods.MyMethod("name", OnMyMethodComplete);
}
function OnMyMethodComplete(result, userContext, methodName) {
alert(result);
}
If you want to call a Web method synchronously, you'll need to set up the request manually and use a Sys.Net.XMLHttpSyncExecutor.
Here's an example (see ExecuteSynchronously function).
For a JavaScript solution, you could loop until name has a value. Adjust time-based on latency to keep app responsive
var time = 100;
window.setTimeout(name == '' ? wait : continue, time);
function wait() {
window.setTimeout(name == '' ? wait : continue, time);
}
function continue() {
//code having to do with name
alert(name);
}
Congratulations! You've taken your first step into a larger asynchronous world. I'd definitely go with using the callbacks that CSharpAtl suggested.

Resources