Well that’s new, in so far as in 2012 the documentation said, avoid DoEvents with RealBasic threads. Good that you are being more explicit about it but the documentation is (still) less than clear.
“Intended for console applications in which there is no main event loop.”
So where do I find the “main event loop” documented?
Main event loop is what keeps your application running/alive, otherwise it would terminate and close. It’s not something you can really use; but can hook-into using OS API’s (which shouldn’t need to be done for anything in all honesty).
**If you’ve ever developed a console application, you’ll note needing to add a loop of sorts (ie Do/Loop - While/Wend) to keep your application running while waiting for & processing data/input. In that case, that would be your “main event loop.” Desktop main event loops are pre-coded in the executable stubs used to compile Xojo applications.
If ever you need to actually ‘pause’ execution in a Xojo Desktop application, it’s recommended to use Thread.Sleep. Don’t use App.DoEvents - it’s bad coding and will result in errors that you’ll have a hard time tracking-down later on.
Aha! I was under the impression, from what I read, that the main thread would not accept the sleep command. I tried it anyway and it gave me a language error. I would love to be able to have the main thread sleep so the other events (ie waiting for communication response) could execute. I just have not found a command that works. No matter what I’ve done, it seems like I produce a “tight loop” that prevents other things to execute. When the main thread finishes the delay I’ve imposed, it continues without the pending events having executed. When the main thread gets done and returns control to the UI and catches up on pending events, it’s too late to use the data. If I put out a number of requests for data, I get all of the data back after the task has executed–not much good to me then.
I disagree. You do thread.Pause() and when an event handler determines that something has happened that the thread needs to take action over, you do thread.Resume().
If there is nothing for your app to do, then it should be doing nothing and none of your code should be executing. Eventually something external will happen. That could be a user mouse click, data arriving from a remote host, or a timer going off, and so on. Any of these causes an event to fire which may result in a thread running or it may not, perhaps all that’s needed is a character being added to a buffer, then an event handler will probably do that. Once the interruption to tranquillity has been taken care of, everything dozes off again until next time.
Indeed - I used the wrong terminology. Pause and Sleep are not used inversely… I purely intended to solely use “SleepCurrent.” - you may disregard ‘pause.’ and Tim is correct, sleeping will ‘hold’ everything’ while the thread ‘sleeps’
Wayne, all you wrote in this thread seems to me that you fight against Xojo‘s event-based concept what causes errors or unexpected behavior.
So, please use the event „DataAvailable“ to get the incoming data, store it in an array and if you detected a defined „end“ of the stream, process it in a thread.
Be aware to keep the main thread „clean“, means, perform long running tasks in threads.
In advance, you can safely try to use Socket.Poll at the end of a DataAvailable and/or SendProgess event. This could speed things up.
Not that I am aware of. Most of what I can tell you about how Xojo works with the network was learnt the long and hard way; reverse engineering with trial and error and deduction. I was once invited to write a book on networking with RealBasic but that was over 10 years ago.
Sorry Matthew, I was having a veiled dig at the documentation. A search of the documentation throws up hundreds of articles that mention “the main event loop” but I couldn’t find one that explained what that was and how it interacts between our own Xojo code and the OS message queue.
When we talk about event loops and event driven, I naturally expect to be talking about message queuing, but that’s not what happens with Xojo. When we talk about threads, I naturally expect to be talking about independent threads of execution, but that’s not what we have in Xojo. What we get with Xojo is a single thread, a single instruction pointer and a lack of clarity in the documentation. Just some vague warning to not use DoEvents in Desktop apps, 'Cos bad things will happen.
What Xojo does seems to be very similar to what I worked on with PDP-11s in the 70s and the VAX in the 80s. As follows.
With the PDP-11s (this was at CERN) we worked at the level of the bare metal. What corresponded to a Xojo event was a hardware interrupt, and the interrupt handler had to determine whether it could do everything itself (such as store a byte from a serial interface) or whether that I/O was in fact complete, and the task that owned the device causing the interrupt needed to be scheduled for execution. If so then that task was marked as runnable, and the task scheduler invoked. Depending on task priorities, that might cause a context switch.
Whenever no real task needed to run, then the lowest priority task could run. We called this the Idle Task, and in Xojo terms it looked like this:
While (True)
HALT
wend
and HALT was the hardware instruction on the PDP-11 to stop the CPU. The CPU then executed no instructions at all until an interrupt occured. If the interrupt handler completed without calling for a task to be scheduled, then the Idle Task resumed execution at the instruction after the HALT.
It seems to me that this corresponds more or less directly to the Xojo event loop, which, when the app has nothing to do, has to tell the operating system that this app needs no cycles at the moment. I’m sure it’s a lot more complicated than that, however.
What we called Tasks in our PDP-11 setup correspond more or less to Xojo threads. My app has two which run permanently, and others come and go as needed. At times there may be several running, and yes they are separate threads of execution.
I’m not quite old enough to have worked on a PDP11. My first commercial project was for an Apple II in the early 80s. I don’t think it can work the way you say though @TimStreater, for two reasons.
i) Modern operating systems insulate userland from interrupts.
ii) Xojo are at pains to point out that Xojo Threads are cooperative. Xojo ‘threads’ may have the appearance of being separate but a thing can not be simultaneously cooperative and independent.
I think it more likely the framework is sitting in a loop, updating an internal representation of the OS state, responding to messages from an OS event queue by calling function pointers to our code. If so, Xojo scheduling can be handled co-operatively, similar to doing two things at once with a micro-controller. All remains well while the instruction pointer remains downstream of the event loop. Xojo can be as busy at it likes, the OS is going to pre-empt the event loop anyway. However, a backwards call to the event loop to force an iteration (DoEvents), might indeed cause, bad things to happen in Xojo land - The iteration would completed and the internal state would be updated, but the stack frame would be carrying pointers to a previous iteration.
I didn’t say that Xojo events are interrupts, I said that they correspond to interrupts when comparing the Xojo model top what we created 50 years ago.
Understood. I am saying Xojo events are nothing like interrupts (and the difference would be pertinent to this thread).
Interrupts occur NOW. No other code can execute between the interrupt occurring and the interrupt being handled. Interrupt handlers are always called in the order they occur.
Xojo events occur sometime in the past. Other code (the framework) will have executed before your Xojo event handler is called. Xojo event handlers may be called other than the order they occur.
The pertinence to the thread is the network, which is continually changing state in strict time order, (truly) independent of the CPU, OS and applications above. - You can not stop the network and step through it, as you can your Xojo code and file i/o. When network comms fails to behave the way you expect, ‘temporal concurrency’ is one of the suspects. (Temporal concurrency being a fancy way to say, state changes occurring in software in the same order they occur in time.)
I was hoping you might get it as you used to program bare metal.
When a function is called the memory address of the line of code being executed (the instruction pointer) is pushed onto the stack along with a copy of local variables (stack frame). When the function returns the stack frame is popped off, the instruction pointer and locals restored, and your code continues to execute at the next line.
If you are sat in an event loop and only call forward, allowing the stack frame to collapse back by returning from each call, all is well. However, were your function to call backwards, causing the event loop to iterate (DoEvents), a change of state may occur. When the stack finally collapses back, the instruction pointer and locals get restored, and your next line of code executes with local values from the earlier state. Indeed, bad things might happen. Where code is operating on a local copy of a global network buffer for instance, there is latitude to end up processing later bytes earlier (phantom buffer).
This is not necessarily the case. Interrupts (in at least some machines) have a hardware priority. That means that while the handler for a lower priority interrupt is running, it may itself be interrupted by a higher priority interrupt, whose handler will then run while the lower priority handler stops execution. Also, if a higher prority interrupt 's handler is running, it won’t be interrupted by a lower priority interrupt. Instead, that lower priority interrupt will enter a pending state and will only be allowed to run after the higher priority handler completes.
In some machine I recall that the last instruction of a handler was named RTI (Return from Interrupt), which signalled the hardware that the handler had finished and it was to return to the running program or to handle the next lower pending interrupt. And it’s possible to disable interrupts, either so that they are ignored altogether, or so that they become pending until that block is removed. There are privileged instructions to do this.
Here’s my problem: My main thread is called upon by the user to perform a sequence of tasks that involve interrogating a piece of test equipment to deliver data, operating on that data, then instructing another piece of equipment to change the parameters of a unit under test, storing the data, getting more data, changing parameters again, and, after numerous itterations, to operate on the data and to store the results to a file. Each step must be completed in sequence, but what I find is that the main thread continues to the next step without waiting for the given step to finish, so that the main thread barrels along and finishes the sequence and then the dataavailable empties the input buffer with all of the accumulated data. This is, of course, useless because the main thread had finished operating on the data arrays that haven’t been filled. I need to have a way to tell the main thread to halt further execution and wait for the anticipated data after making a data request.
I have found that out: Sleep (or a do.(nothing) loop to stall for time blocks everything. Xojo acts like some people I know: I have it ask a question (make a data request through the internet) and then it continues without waiting for an answer to the question.
This really sounds like you need to put your sequential operations into a Thread.
A thread can then do things like
Thread1.Run()
// process step 1
send("doStep1")
While AwaitingResonpse()
sleep(100) ' sleep for 100 milliseconds
wend
if response <> "step1 Completed" then
goto Error
end if
// process step 2
send("doStep2")
While AwaitingResonpse()
sleep(100) ' sleep for 100 milliseconds
wend
if response <> "step2 Completed" then
goto Error
end if
My experience with events, such as dataavailable, is that cannot find a way to have the main loop halt exectution to wait for the event to occur. While the external equipment is processing the data request and responding, the main thread barrels along trying to process data that hasn’t arrived and issuing commands for more data. By the time the event fires (200 msec), the main thread has completed its task on non-existent data. Then the event fires and dumps everything, which at that point has no usefulness.