0

First of all, I learned Python on my own from online tutorials and (mostly) learning by doing, so I might did some strange things in my code. :) So, I am working om my first bigger project with Raspberry Pi, and for that I need codes running parallel. I wrote this part of my code for managing a simple D-pad:

Problematic code

import threading
import time
import pigpio


# input from the D-pad goes to these pins
BUTT_UP = 12
BUTT_LEFT = 16
BUTT_CENTER = 25
BUTT_RIGHT = 20
BUTT_DOWN = 21


class dpad_monitoring(threading.Thread):
    '''thread for monitoring the D-Pad'''

    def __init__(self, thread_ID, butt_up, butt_left, butt_center, butt_right, butt_down, res = 10.00):

        threading.Thread.__init__(self)
        self.running = True
        self.thread_ID = thread_ID

        # number of checks per sec
        self.res = res

        # key pins
        self._pins = [butt_up, butt_left, butt_center, butt_right, butt_down]

        #key monitor
        self.last_pressed = 0

        '''key numbers:
         UP      LEFT    CENTER     RIGHT     DOWN
          1       2        3          4         5       '''

        # setting up GPIO
        self.pi = pigpio.pi()
        for i in range(0, len(self._pins)):
            self.pi.set_mode(self._pins[i], pigpio.INPUT)
            self.pi.set_pull_up_down(self._pins[i], pigpio.PUD_UP)

    def stop(self):
        '''stopping the thread cleanly'''
        self.pi.stop()
        self.running = False

    def run(self):
        '''checks which button is pressed as many times per sec as specified 
            in the res variable in init. If any of them is pressed, it suspends itself
            until self.last_pressed is set to 0 again by main()'''


        while self.running:

            states = []
            for i in range(0, len(self._pins)):
                state = not self.pi.read(self._pins[i])  # pi.read returns 1L if the pin is high, 
                states.append(state)                #   what means the button is not pressed, 0L when pressed

            for i in range(0, len(states)):
                if states[i]:
                    self.last_pressed = i+1

            '''UGLY AS SHIT but works now, will change to locks after the code works'''
            if self.last_pressed != 0 :
                while self.last_pressed != 0:
                    pass
            else:
                time.sleep(1/self.res)


            print 'im groot'  # for debugging



def main():

    print 'ok' #debug

    dpad = dpad_monitoring(0, BUTT_UP, BUTT_LEFT, BUTT_CENTER, BUTT_RIGHT, BUTT_DOWN)
    dpad.run()

    print 'okey' #debug again 

    while i != 3:

        i = dpad.last_pressed
        if i == 1:
            print 'UP'
            dpad.last_pressed = 0
        if i == 2:
            print 'LEFT'
            dpad.last_pressed = 0
        if i == 4:
            print 'RIGHT'
            dpad.last_pressed = 0
        if i == 5:
            print 'DOWN'
            dpad.last_pressed = 0

    print 'CENTER, stopping'
    time.sleep(0.5)
    dpad.stop()

if __name__ == '__main__':
    main()

The problem is when I run the code, I get this:

ok
im groot
im groot
im groot
im groot
im groot
im groot

... (endless groot)

So it seems the code gets stuck at dpad.run(). Now AFAIK, the main point of threading is that the code continues after calling the run() function and can interact with the threading object, so I don't know what the he'll is going on. Could you, all experts, help me out please? (Since the code after dpad.run() never ran, I don't know if it works, it may be all garbage. :P

The strange thing is that this simple test code works with no problem:

Cool code:

import threading
import time

class thread1(threading.Thread):

    def __init__(self, threadID, start_from):
        threading.Thread.__init__(self)
        self.threadID = threadID
        self.i = start_from
        self.running = True

    def run(self):
            while self.running:
                time.sleep(1)
                self.i = self.i+1

    def stop(self):
        self.running = False

class thread2(threading.Thread):

    def __init__(self, threadID, start_from):
        threading.Thread.__init__(self)
        self.threadID = threadID
        self.i = start_from
        self.running = True

    def run(self):
            while self.running:
                time.sleep(0.5)
                self.i = self.i+10

    def stop(self):
        self.running = False

thread1 = thread1(1, 10)
thread2 = thread2(2, 1)

thread1.start()
thread2.start()

for j in range(30):
    print thread1.i, thread2.i
    time.sleep(0.3)

thread1.stop()
thread2.stop()

The output is

10 1
10 1
10 11
10 11
11 21
11 31
11 31
12 41
12 41
12 51
13 61
13 61
13 71
13 71
14 81
14 91
14 91
15 101
15 101
15 111
16 121
16 121
16 131
16 131
17 141
17 151
17 151
18 161
18 161
18 171


------------------
(program exited with code: 0)
Press return to continue

So there I got the main thread plus the two other run parallel, unlikely to the previous code. What the he'll is going on?

4
  • 1
    You need to call dpad.start(), not dpad.run(). Using run() makes the code run in the main thread, rather than a background thread. Your second example uses start(), which is why it runs just fine. Commented Oct 30, 2015 at 17:52
  • O damm, really, I am full idiot. Thank you. I do not have experience in debugging too :P Commented Oct 30, 2015 at 17:56
  • also IIRC threading will only run your code concurrently, you won't get any parallel (multiple processor threads / cores) advantages - wiki.python.org/moin/GlobalInterpreterLock Commented Oct 30, 2015 at 18:13
  • @KarlC Interesting... I knew the threading class does not provide actual multithreading, but since the Pi is single-cored, it does not matter anyway. Commented Oct 30, 2015 at 18:27

1 Answer 1

2

Instead of

dpad.run()

do

dpad.start()

When calling run() directly you are skipping the whole threading functionality and using it as a regular class.

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you, already figured this out thanks to dano's comment on the question. Now it works, but I have to find a method to pause the thread until the main thread "reads" the button code. I don't see yet how to do this with locks...
@user4729 only pass data to thread in a Queue. For example, if you need to pass button code, the thread will stop and wait for the queue item until the main thread puts it there. Trying to access the same objects in memory will result in concurrent access with unpredictable results.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.