If I then call Thread.Suspend, does the thread suspend at the current instruction i.e. it could suspend at any one of the instructions in the loop? Then when I call Thread.Resume would execution continue from the instruction at which I called the suspend?
I assume you mean, “if I then call Thread.Suspend from the main or different Thread”? If so, keep in mind that Threads are cooperative, not preemptive, so, in a sense, the Thread was already suspended by the time it gets to your call. It simply won’t resume normally.
The context switches happen at loops so it will probably be at the “wend” statement.
Unfortunately, that is no longer the case now that portions of the framework are written in Xojo and may contain loops which will allow a context switch. Assume that a context switch can happen anywhere. But to answer the original question, your code will pick up where it left off. Context switching and thread suspension will not alter the flow of execution of the code within the thread.
Thanks, I think you have answered my question Tim. So for example, say another thread (or main thread) is testing b for a value and it will call suspend if b meets a certain criteria, when I resume, the next instruction (I hope) will be c = d + e.
Kem, I think you are saying my loop will continue to execute regardless of where suspend is called until the loop boundary at which point it will be suspended and then resume will continue from the boundary at which it was suspended.
I think either of the above will suit me, what I don’t want is the loop suspending half way through and then the resumption to be from the end of the loop for example.
No, that isn’t exactly correct. The other thread will see the value of b only when the current thread yields. Given your example code, the thread will only yield at the loop boundary, since you’re not calling anything that might yield. I was speaking to the more general case, where you can no longer make as many assumptions about yielding or not.
Edit: Joe jumped in while I was typing.
Edit: and the loop may run several times after b reaches the criteria before it actually yields. Unless you are explicitly yielding, make no assumptions.
I’m writing a CNC application which interprets GCODE. The interpreting is done within and thread and sent out to on a serial port to the CNC controller. Every now and then the thread needs to be suspended to suit the feed rate of the machine or if the machine hits a limit switch or if the user pauses machining and then needs to continue on where it left off.
Just to complicate matters, I am re-adapting this routine from some python code where you may know python threading is very different.
That makes sense, and suggests an alternate approach, if you’ll consider it.
Rather than trying to control the rate at which the data is created, control how fast, or whether, it’s sent instead.
Create a PacedWriter class that implements the Writeable interface. Its Constructor will take and store a Writeable object and it will have two properties, Period and MaxBytesPerWrite. The Period can be a computed property that ties directly to a Timer created at Construction.
Every time you call Write, the data you are trying to send will be amended to a variable instead and the Timer started, if needed.
On Timer.Action, the MaxBytesPerWrite will be written from the buffer, and the buffer reduced accordingly. You can create events that a subclass can use to provide further control, and a computed property to return the attached Writeable.
This is all theory, of course, but I imagine it would look something like this:
Sub Constructor (w As Writeable)
mMyWriteable = w
WriteTimer = new Timer
AddHandler WriteTimer.Action, AddressOf HandleWriteTimer
End Sub
Private Sub Destructor ()
if WriteTimer isa Timer then
WriteTimer.Mode = Timer.ModeOff
RemoveHandler WriteTimer.Action, AddressOf HandleWriteTimer
WriteTimer = nil
end if
End Sub
Sub Write (data As String)
Buffer = Buffer + data
if WriteTimer.Mode = Timer.ModeOff and not IsSuspended then
WriteTimer.Mode = Timer.ModeMultiple
end if
End Sub
Sub HandleWriteTimer (sender As Timer)
dim data as string = Buffer.LeftB( MaxBytesPerPeriod )
if not RaiseEvent WritingData( data ) then
Buffer = Buffer.MidB( data.LenB + 1 )
MyWriteable.Write data
end if
if buffer = "" then
sender.Mode = Timer.ModeOff
end if
End Sub
Buffer is a class property and IsSuspended is a computed class property that would turn on and off the Timer as needed. The WritingData event would give the subclass a chance to control the flow further.
One thing if you use any part of my posted code: I should have used “WeakAddressOf” instead of “AddressOf” when setting up the handler. Otherwise, the Destructor will never fire.