threading - thread starts, but main does not run



  • Hi All,

    I want to run a thread in the background, reading I2C GPS pytrack data and feeding a micropyGPS object to constantly update GPS/GNS data.

    In the main thread I want to read from the same micropyGPS object to occasionally update location data.

    I have a main.py that does;

    my_gps = MicropyGPS()
    py = Pytrack()
    L76micropyGPS = L76micropyGPS(my_gps, py)
    while (True):
        print("my_gps.parsed_sentences : {}".format(my_gps.parsed_sentences()))
        time.sleep(2)
    

    This creates creates the object that then starts a thread thus;

    class L76micropyGPS:
    
        GPS_I2CADDR = const(0x10)
    
        def __init__(self, my_gps, pytrack=None, sda='P22', scl='P21'):
            <snippage>
            self.my_gps = my_gps
            # start thread feeding microGPS
            _thread.start_new_thread("GPS", self.feedMicroGPS(), ())
    
        def feedMicroGPS(self):
            print('Running feedGps_thread id: {}'.format(_thread.get_ident()))
            someNmeaData = ''
            while True:
                # get some NMEA data
                someNmeaData = str(self.i2c.readfrom(GPS_I2CADDR, 128))
                print(" feedGps_thread - gpsChars recieved : {}".format(len(someNmeaData)))
                # Pass NMEA data to micropyGPS object
                for x in someNmeaData:
                    self.my_gps.update(str(x))
                time.sleep(2)
    

    Actual behaviour - I see the thread start, and get I2C data, whilst updating the object, but the main thread never gets beyond creating that object - ie the while loop never executes.

    My expected behaviour is the thread runs in the background (in this case printing data) and then the main thread carries on running (and can see the new GPS data).

    Have I mis understood something about _threading on micropython?

    Complete code: https://github.com/gregcope/L76micropyGPS







  • @timh said in threading - thread starts, but main does not run:

    @gregcope Sorry I missed the arglist 2nd argument altogether.

    I was focusing on the first arg, where you were still calling a function/method and passing it's result to start_new_thread rather than passing the function handle.

    As to bug, that probably should raise an expecption, but thats in the _thread library

    No problem - thanks for all your help.

    @Seb - where do i raise bugs?



  • @gregcope Sorry I missed the arglist 2nd argument altogether.

    I was focusing on the first arg, where you were still calling a function/method and passing it's result to start_new_thread rather than passing the function handle.

    As to bug, that probably should raise an expecption, but thats in the _thread library



  • @timh Many thanks.

    self.gps_thread = _thread.start_new_thread(self.feedMicroGPS)
    

    I found that did NOT work.

    But

    self.gps_thread = _thread.start_new_thread(self.feedMicroGPS, ())
    

    Does work - ie you have to supply an empty arg list, otherwise it does not return.

    Is that a bug? Should it not throw an exception?



  • @gregcope Hi Greg.

    You missed the crucial bit in my email. You code still callsself.feedMicroGPS() once and it's result is passed to start_new_thread.

    self.gps_thread = _thread.start_new_thread(self.feedMicroGPS())

    should be

    self.gps_thread = _thread.start_new_thread(self.feedMicroGPS)



  • Thanks @timh tried that (or something similar);

    Changed main to include;

    L76micropyGPS = L76micropyGPS(my_gps, py)
    
    gpsThread = L76micropyGPS.startGPSThread()
    print("startGPSThread thread id is: " + startGPSThread)
    

    And class L76micropyGPS to (separate out the thread start to its own method, so I can call thread stop in another method);

        def startGPSThread(self):
            # start thread feeding microGPS
            self.gps_thread = _thread.start_new_thread(self.feedMicroGPS())
    

    My expected behavour is that the Main thread gets to this line just after thread start and Main carries on (with Thread in background also carrying on;

    print("startGPSThread thread id is: " + startGPSThread)
    

    This never happens ....
    Output (that just carries on)

    Free Mem: 2535984
    Free Mem post pytrack instantiation: 2534320
    Free Mem post my_gps instantiation: 2533616
    Running feedGps_thread id: 1073503820
     feedGps_thread - gpsChars recieved : 226
     feedGps_thread - gpsChars recieved : 139
     feedGps_thread - gpsChars recieved : 141
     feedGps_thread - gpsChars recieved : 139
    


  • @gregcope Have a look at the docs and your call to start_new_thread

    _thread.start_new_thread(function, args[, kwargs])
    Start a new thread and return its identifier. The thread executes the function with the argument list args (which must be a tuple). The optional kwargs argument specifies a dictionary of keyword arguments. When the function returns, the thread silently exits. When the function terminates with an unhandled exception, a stack trace is printed and then the thread exits (but other threads continue to run).

    At the moment you are passing in a 'string' GPS as the first argument and the result of the function call self.feedMicroGPS() in the second.

    Your start_new_thread call should look like _thread.start_new_thread(self.feedMicroGPS, <some args>)

    When the docs say pass a function, your are passing a function/method handle and not calling the function.


Log in to reply
 

Pycom on Twitter