Comyar D
Comyar D

Reputation: 302

Global variable's value doesn't change in a thread

I'm making a flask application, and when the user presses a button I want for a thread to pause until the button is pressed again, and i'm planning to do this with a flag being set off. The thread can read the initial value of the flag, but when the user presses the button and the value is changed, the value remains false in the thread. It can read it successfully, but it just can't change it. I've tried making it global but it still has no effect. Here is the source -

web = False

@app.route("/")
def bg_func():
   print('Thread test')
   while True:
      if web == False : 
         if Facial_Check.run()  == True: 
            face_detected = True

t = Thread(target=bg_func)
t.start()

@app.route("/<changePin>/<action>")
def action(changePin, action):
   changePin = int(changePin)
   deviceName = pins[changePin]['name']

   global web
   
   if action == "on":
      GPIO.output(changePin, GPIO.HIGH)
      time.sleep(1)
      GPIO.output(changePin, GPIO.LOW)
      
      web = True
      current_status = True
      message = "Turned computer on."

   if action == "off":
      GPIO.output(changePin, GPIO.HIGH)
      time.sleep(1)
      GPIO.output(changePin, GPIO.LOW)
      
      web = False
      current_status = False
      face_detected = False

      message = "Turned computer off."

   for pin in pins:
      pins[pin]['state'] = GPIO.input(pin)

   return render_template('index.html', Status=current_status)

Upvotes: 2

Views: 98

Answers (1)

rzlvmp
rzlvmp

Reputation: 9364

You should use thread-specific features to be able share data between threads.

You may use current_thread for these purposes:

from flask import Flask
from time import sleep
from threading import Thread, current_thread

app = Flask(__name__)
web = current_thread()

def bg_func():
   i = 0
   while i < 100:
      i += 1
      sleep(2)
      print('web is', getattr(web, 'web', None))

@app.route("/<my_web>")
def index(my_web = '0'):
    before = getattr(web, 'web', None)

    if my_web == '1':
        setattr(web, 'web', True)
    else:
        setattr(web, 'web', False)
    
    after = getattr(web, 'web', None)
    
    return f"set {before} to {after}"

if __name__ == '__main__':
    setattr(web, 'web', False)
    t = Thread(target=bg_func)
    t.start()
    app.run(host='127.0.0.1', port=8080)

browser output will be:

set False to True

when access http://127.0.0.1:8080/1 first time

terminal output will be:

web is False
web is False
web is True
web is True
...

Update: adding example with socket client →

I added socket listeners as in your example:

  • Server side
from flask import Flask
from time import sleep
from threading import Thread, current_thread
from flask_socketio import SocketIO

def bg_func():
   print('Thread test')
   while True:
      sleep(1)
      print('web is ' + str(web.web))

app = Flask(__name__)
web = current_thread()
socketio = SocketIO(app)
setattr(web, 'web', None)

@app.route("/")
def action():
   return 'web is ' + str(web.web)
      
@socketio.on('connect')
def connect():
   setattr(web, 'web', True)
   print('Client connected to server ')
   
 
@socketio.on('disconnect')
def disconnect():
   setattr(web, 'web', False)
   print('Client disconnected from server ')
    
if __name__ == "__main__":
   t = Thread(target=bg_func)
   t.start()
   socketio.run(app, host='127.0.0.1', port=7878, debug=False)
  • Client side:
import socketio
sio = socketio.Client()
sio.connect('http://127.0.0.1:7878')

When I using client the output at server side is looking like:

...
web is None
web is None
...
Client connected to server 
web is True
web is True
...
Client disconnected from server 
web is False
web is False
...

BUT!

as you can see here is debug=False in my code. That is because of Flask run two app threads in DEBUG mode.

So first of web is controlled by you, second one is never changing and always will show None (if you change debug to True).

Upvotes: 2

Related Questions