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

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;
}
}

Related

Qt - start process with click event and stop it again with the second click event

I found time to investigate a bit into QT, and it is very interesting for me. However, right now I am encountering a problem that I am not aware about how to solve it. My aim is actually simple. I have a QCheckBox that I want to activate. If it is activated, I am starting a process (I am opening a file, reading it, taking some values out and change different labels accordingly). This process is repeated until the user is deactivating the QCheckBox. Some small code example to get a better idea of what I am going to do.
void Analyzer::on_actualTemperature_stateChanged(int arg1)
{
// Read data and change labels
if (arg1 != 0)
{
qDebug() << "Start data analysis";
// Infinity loop to get the data and display it
while true
{
// Open file and extract data
const actualTemperature = getData();
// Change any label or do something with the data
ui->anyLabel->setText(actualTemperature);
// Some break
QThread::sleep(1);
// Leave the loop if user deactivate the QCheckBox
// Something like on_actualTemperature_stateChange == 0
}
}
// Stop reading the data
else
{
qDebug() << "Stop data analysis";
}
}
It is obvious that after activating the QCheckBox, the loop will not finish at all and the GUI will not recognize anything anymore. Hence, I guess I have to start some new thread and have to kill it. However, I have no idea how to proceed here. An idea would be:
void Analyzer::on_actualTemperature_stateChanged(int arg1)
{
// Read data and change labels
if (arg1 != 0)
{
// Start reading the file and updating the label using some other thread
startThread(XY);
}
// Stop reading the data
else
{
// Kill thread 1234
killThread(XY);
}
}
Any hint is warmly welcomed and I hope this question is not too basic for you. Thank you for reading, Tobi.
I think killing a running thread is not a decent behavior. Let's be gentle to our threads with a loop control variable. In this example it named keepLoop. Set keepLoop when checkbox checked. Then start thread if it is not running. We are using QtConcurrent::run, and monitoring it by a QFuture in this case.
connect(ui->checkBox, &QCheckBox::toggled,
[&](const bool checked) {
analyzer->keepLoop = checked;
if (checked && !future.isRunning())
future = QtConcurrent::run(analyzer, &Analyzer::on_actualTemperature_stateChanged);
}
);
Don't call user interface slots directly, instead connect them to signals. Connections will be queued connection when signals emitted from another thread. It means slots will be called in event loop of main thread and changes will be shown when the next frame painted.
connect(analyzer, &Analyzer::temperatureCalculated, ui->anyLabel, &QLabel::setText);
Our asynchronous function does not forced to die immediately when user toggle checkbox. Instead we letting it to finish the iteration it already on halfway through.
Analyzer::on_actualTemperature_stateChanged() {
while (keepLoop) {
// Open file and extract data
const QString& actualTemperature = getData();
// send data
emit temperatureCalculated(actualTemperature);
}
}
You can use atomic bool if you want a more precise loop control.
Bonus:
If you don't want to mess with threads, you can avoid GUI freezing by using QTimer to run your loop periodically in main thread.

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;
}

What is the proper way of disposing a QMessageBox instance?

given this code:
void FooBar::ProcessExitHandler(QProcess* someProcess, QString logsPath)
{
if (clientProcess->exitCode() != 0)
{
QMessageBox* dialog = new QMessageBox();
dialog->setText("bye bye");
dialog->setStandardButtons(0);
QObject::connect(dialog, &QMessageBox::finished, [this](int) {
if (mMainWindow->AutoCloseCheckBoxChecked())
{
delete dialog; //TODO: need to confirm what is the correct way
this->quit();
}
});
dialog->show();
dialog->activateWindow();
}
else
{
if (mMainWindow->AutoCloseCheckBoxChecked())
{
delete dialog; //TODO: need to confirm what is the correct way
this->quit();
}
}
}
Is calling delete dialog like that correct? Is there a more QT idiomatic way of doing this?
Also, something that has caused me confusion is the idea (from the docs) that I should be passing a parent to the constructor of the message box. Then I would get automatic memory management, right? Is that the QT style I should shoot for?
I'm aware that since the app is exiting anyway, the leak "doesn't matter", but I want to do the right thing.
The right way is to use setAttribute
QMessageBox* dialog = new QMessageBox();
dialog->setAttribute(Qt::WA_DeleteOnClose);
By setting the attribute WA_DeleteOnClose, the destructor will be called at the right moment.
When you manually call delete, the pointer will keep its value (the address) although it isn't valid anymore. If for some reason you were to reuse that pointer again, the app would crash.
\warning Deleting a QObject while pending events are waiting to be
delivered can cause a crash. You must not delete the QObject directly
if it exists in a different thread than the one currently executing.
Use deleteLater() instead, which will cause the event loop to delete
the object after all pending events have been delivered to it.
https://code.woboq.org/qt5/qtbase/src/corelib/kernel/qobject.cpp.html#881

Exception reason/message. Am I reinventing the wheel here?

I want some kind of mechanism to have more information about a caught exception. (Specifically exceptions I throw myself to abort transactions) I've looked around and pretty much the only thing I could find was "Use the info log". This to me does not seem like a good idea. For one it is cumbersome to access and find the last message. And it is limited in size so at some point the new messages won't even show up.
So my idea is the following: Create a class NuException and pass an instance of that through all methods store an instance in the class where the work methods are located. When I need to throw an exception I call a method on it similar to Global::error() but this one takes an identifier and a message.
Once I reach my catch block I can access those from my object the class that contains the work methods similarly to how CLRExceptions work.
class NuException
{
"public" str identifier;
"public" str message;
public Exception error(str _id, str _msg)
{
//set fields
return Exception::Error;
}
}
class Worker
{
"public" NuException exception;
void foo()
{
throw this.exception.error("Foo", "Record Foo already exists");
}
void bar()
{
this.foo();
}
}
void Job()
{
Worker w = new Worker();
try
{
w.bar(ex);
}
catch (Exception::Error)
{
info(w.exception().message());
}
}
It works but isn't there a better way? Surely someone must have come up with a solution to work around this shortcoming in AX?
Short answer: yes.
While your "brilliant" scheme "works", it gets boring pretty fast, as you now must transport your NuException object deep down 20 level from the listener (job) to the thrower (foo). Your bar method and other middle men has no interest or knowledge about your exception scheme but must pass it on anyway.
This is no longer the case after the update.
There are several ways to go.
Use an observer pattern like the Event broker or in AX 2012 and newer use delegates.
Stick to the infolog system and you use an InfoAction class to peggy bag your information to be used later. It can be used to display a stack trace or other interesting information.
Use a dedicated table for logging.
The third way may seem impractical, as any errors will undo the insert in the log. This is the default behavior but can be circumvented.
MyLogTable log;
Connection con = new UserConnection();
con.ttsBegin();
log.setConnection(con);
... // Set your fields
log.insert();
con.ttsCommit();
Your way to go depends on circumstances you do not mention.

BackgroundWorker.RunWorkerCompleted event in WPF

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.

Resources