Thread.Suspend

If I have a loop within a thread i.e:

while 1 < 2 a = b + c b = c + d c = d + e wend

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.

Assuming the absence of operator overloads or computed properties, there is no way for that code to cause a context switch in the loop body.

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.

Thanks Tim.

Ok, So Joe, if b is a computed property whose setter has a thread.suspend are you saying there would be a context switch when b’s value changes?

I’m curious. What problem are you trying to solve?

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.

Off the top of my head, of course…

+100

And do whatever you can to keep the main thread as responsive as possible.

Thanks guys. Much appreciated. That’s given me plenty to chew on. I’ll get back to the keyboard. Very helpful.

Sounds good Mike.

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.