ameypg
ameypg

Reputation: 23

Python - Polling a variable

I change a global variable in a signal handler and poll for it in the main program. But the value does not change in the main thread.

Is there a qualifier that I need to use to make it a volatile (like in Java) variable?

Here's the program:

test.py

import time
import signal

def debug():
    closeSession = False

    def sigint_handler(signal, frame):
        global closeSession

        print('Breaking the poll...')
        closeSession=True

    signal.signal(signal.SIGINT, sigint_handler)

    # Start a program...

    while not closeSession:
        time.sleep(1)
        print('Polling... closeSession = %r' % closeSession)

    print('Exiting! Bye.')
    # Sent 'quit' to stdin of the program

if __name__ == "__main__":
    debug()

sigint_handler() gets called whenever I press Ctrl + C but the new value of closeSession is not used in the main thread.

I get the following output:

$ python test.py
Polling... closeSession = False
Polling... closeSession = False

I press Ctrl + C

^CBreaking the poll...
Polling... closeSession = False

Press Ctrl + C, again

^CBreaking the poll...
Polling... closeSession = False

Press Ctrl + C, again

^CBreaking the poll...
Polling... closeSession = False
Polling... closeSession = False

Upvotes: 2

Views: 1870

Answers (2)

overactor
overactor

Reputation: 1789

The problem is scope.

Inside the debug() function, you didn't declare closeSession as a global, which means that you have two variables called closeSession. One global and one scoped within the debug() function. And inside the sigint_handler() function, you've explicitly instructed to use global one, which is shadowed by the scoped one in the outer function.

You can solve this by declaring global before assignment in debug():

def debug():
    global closeSession
    closeSession = False
    ...

By the way, your code does not work on windows, it throws a IOError because the sleep function is interrupted. A workaround that worked for me is:

...
while not closeSession:
    try:
        time.sleep(1)
    except IOError:
        pass
    print('Polling... closeSession = %r' % closeSession)
...

It's not pretty but it works.

Upvotes: 3

adrianus
adrianus

Reputation: 3199

You have to set global closeSession before accessing the variable, else you're creating a local variable with the same name and the loop will never end.

Try this:

import time
import signal

def debug():
    global closeSession # <-- this was missing
    closeSession = False

    def sigint_handler(signal, frame):
        global closeSession
        print('Breaking the poll...')
        closeSession=True

    signal.signal(signal.SIGINT, sigint_handler)

    # Start a program...

    while not closeSession:
        time.sleep(1)
        print('Polling... closeSession = %r' % closeSession)

    print('Exiting! Bye.')
    # Sent 'quit' to stdin of the program

if __name__ == "__main__":
    debug()

Upvotes: 1

Related Questions