Can't kill thread - not defined

So I’m using a thread to flash a stack light.

– edit - note the asterisks are added by the site when I bold the code

Simple function to start it flashing:

def start_flash():

** warning_1 = run flash_yellow()**
end

. . . . . and here’s the function to stop the flashing:

def clear_flash():

** kill warning_1 #shut off flashing yellow**

** end**

However, I’m getting a compile error:
name ‘warning_1’ is not defined

If I comment out the “kill” line, the light flashes as expected.

What’s up with the kill command?

For completeness, here’s the actual thread code:

thread flash_yellow():

** while True:**
** set_configurable_digital_out(5, True)**
** sleep(0.5)**
** set_configurable_digital_out(5, False)**
** sleep(0.5)**
** end**
end

You are creating the thread inside of a function.
Variables created inside of a function have a local scope and are not automatically accessible outside of that function.
You can fix this by adding the keyword global before warning_1 when you run the thread (inside def start_flash())

def start_flash():
  global warning_1 = run flash_yellow()
end

warning_1 will then be accessible inside all other functions.

See the Urscript reference under 8. Scope

Thanks

It’s always the stupid mistakes that get me.

1 Like

So, an extension of this issue:

I have an Event tied to a pushbutton – when the button is pressed, several things happen:

  1. clear an array;
  2. turn off the LED in the pushbutton;
  3. kill the flashing yellow thread IF it happens to be running (may not be).

However, if that thread isn’t running, I get an error that the warning_1 variable isn’t initialized.
Is running the thread:

warning_1 = run flash_yellow()

the only way to initialize it?

I just double checked because I thought I ran into a similar thing with my CAP, and it looks like I just set it equal to 0 at the start lol. So in your beforeStart sequence you could just say warning_1 = 0.

2 Likes

I’ve tried setting it to zero and setting it to False - neither seems to work.
If I just start the flasher - I get a quick flash and all is good.

However, the reason I’m doing this is to cancel the flashing light if it’s already on (rack full warning).
In that case, when I press the button it keeps flashing - the flashing changes slightly when the button is pressed, but then continues on flashing.
I haven’t found a way to actually kill the flasher thread from within the Event.

I also tried using the Event to set a variable, then used a separate thread to watch that variable & try to kill the thread. The only thing that would accomplish was, depending on where in the flash cycle the button was pressed, was to change the frequency of the flash - making it strobe instead of .5s on/ .5s off.

Summary - If I start and kill a flasher thread within the Event (button press), it works. If the flasher thread is already running, I can’t seem to kill it with either an Event or another Thread.

I would approach it in a different way:

Instead of running a thread when its needed I would always run a thread and set a variable.

It could look like this:

global WarningLevel = 0 

thread Signal_Light():
  while True: 
    if WarningLevel == 1:
      # Flash DO5 - Yellow
      set_configurable_digital_out(5, True)
      sleep(0.5)
      set_configurable_digital_out(5, False)
      sleep(0.5)
    elif WarningLevel == 2: 
      # Flash DO6 - Red
      set_configurable_digital_out(6, True)
      sleep(0.5)
      set_configurable_digital_out(6, False)
      sleep(0.5)
    end

    sync() 
end

signallamp = run Signal_Light()

The Thread runs always.
It checks what the warning level is and flashes the corresponding light.
You dont have to kill and rerun it.
If you want the light to start or stop flashing you simply change the warning level.

I like that approach - however, I can’t get it to work:

I wrote this test program:

and this is the script:


thread Signal_Light():
if WarningLevel == 0:
# Flash DO6 - Green
set_configurable_digital_out(6, True)
sleep(1.5)
set_configurable_digital_out(6, False)
sleep(0.5)
elif WarningLevel == 1:
# Flash DO4 - Red
set_configurable_digital_out(4, True)
sleep(0.5)
set_configurable_digital_out(4, False)
sleep(0.5)
elif WarningLevel == 2:
# Flash DO5 - Yellow
set_configurable_digital_out(5, True)
sleep(0.5)
set_configurable_digital_out(5, False)
sleep(0.5)
elif WarningLevel == 3:
# Flash DO7 - Blue
set_configurable_digital_out(7, True)
sleep(0.5)
set_configurable_digital_out(7, False)
sleep(0.5)
end

sync()
end


When I run the program, the green light comes on for the first 1.5s pulse, then goes out and nothing else lights up – even though I see it scrolling through each of the wait commands.
I tried breaking it up into separate threads with no change.

Wrap the whole thread’s executing code in a “while(true):” loop. Your thread is executing all the way through to the final “End” command, at which point it’s terminating.

I typically let all my threads run all the time (unless you start pushing the 50 thread limit) and do so like this:

thread myThread():
  while(true):
    if(runThreadVariable == False):
      sync()
    else:
      #put your executing code here
    end
  end 
end

This lets you use “runThreadVariable” anywhere in your main program to, essentially, “turn on/off” the thread without actually worrying about initializing and killing. And as you can see, the “while true” loop is what keeps it always checking.

1 Like

Thanks - works perfectly!

I know I’ve seen that format on a number of examples, but didn’t think to try it here.

still get confused by where the sync() needs to be, but this is working:

thread Signal_Light():
while(True):
if WarningLevel == 0:
# Flash DO6 - Green
set_configurable_digital_out(6, True)
sleep(1.5)
set_configurable_digital_out(6, False)
sleep(0.5)
elif WarningLevel == 1:
# Flash DO5 - Yellow
set_configurable_digital_out(5, True)
sleep(0.5)
set_configurable_digital_out(5, False)
sleep(0.5)
elif WarningLevel == 2:
# Flash DO4 - Red
set_configurable_digital_out(4, True)
sleep(0.5)
set_configurable_digital_out(4, False)
sleep(0.5)
elif WarningLevel == 3:
# Flash DO7 - Blue
set_configurable_digital_out(7, True)
sleep(0.5)
set_configurable_digital_out(7, False)
sleep(0.5)
end
end

sync()
end

I start it with this line in BeforeStart:

image

and then set the WarningLevel when needed:
image

sorry, forgot about the while loop.
That is of course necessary, the thread will not run indefinitely otherwise.

The sync is not necessary anymore because you always have a sleep command in the while loop.

The sync is necessary if you have very short instructions that get called over and over.