Solved Thread started within script prevents XBMC to close normally
#1
Question 
I am scratching my head on this one, and this clearly deserves a fresh look.

I wrote a script that is started upon XBMC startup, which perdiodically fetches some data from several files, URLs, etc. That data is then used in a modded skin of mine. If you are curious, the thread fetches temperature from my weather station, as well as generates some graphs (see this old post of mine).

The system works perfect, but there is an issue when I want to exit xbmc (pression the shut down button on the gui, for example), at this point xbmc just freezes (screen is dimmed and the RSS feeds stop scolling). This goes for several minutes, and then finally xbmc closes. I know that this is my thread which has slopped is sleep cycle and which then releases xblc to close normally.

I think I am not using pytho threads properly, here is my code (launched at XBMC startup) :
Code:
import xbmc, xbmcgui

class MeteoThread (threading.Thread):
  
  def __init__(self, threadID, sleeptime):
    self.threadID = threadID
    self.sleeptime = sleeptime
    threading.Thread.__init__(self)
    self.setDaemon(True)
  
  def run(self):
    while 1==1:
      #do some stuff that takes about 10 seconds
      ... xyz ...
      print "[MeteoThread] fetching data complete, now sleeping "+str(self.sleeptime)+" seconds"
      time.sleep(self.sleeptime)

print "[Meteo] starting..."
HomeWindow = xbmcgui.Window( 10000 )
pollingthread = JCMeteoThread(0, 60*30)
pollingthread.start()
print "[Meteo] started"


This is what I see in my logs
Code:
15:56:48 T:140168616228736  NOTICE: stop python
15:56:53 T:140168616228736   ERROR: XBPyThread::stop - script didn't stop in 5 seconds - let's kill it
But apparently, XBMC does not manage to kill this thread. I used the setDaemon on thread initialization but this did not change anything.

Any suggestion?

V.
Reply
#2
On Frodo have a look to xbmc.Monitor class. It has an abortRequested() Method which will be called from xbmc when xbmc wants to exit.
My GitHub. My Add-ons:
Image
Reply
#3
as mentioned above, your script needs to listen for abortRequested notifications (this can be done without the monitor class).

second, don't put your script to sleep for a long time, as it won't be able to act on the abortRequested call until the sleep period is over.

i would suggest to use something like this:

Code:
def run(self):
    while (not xbmc.abortRequested):
      #do some stuff that takes about 10 seconds
      ... xyz ...
      print "[MeteoThread] fetching data complete, now sleeping "+str(self.sleeptime)+" seconds"
      count = self.sleeptime
      while (not xbmc.abortRequested) and count > 0:
        count -= 1
        time.sleep(1)
Do not PM or e-mail Team-Kodi members directly asking for support.
Always read the Forum rules, Kodi online-manual, FAQ, Help and Search the forum before posting.
Reply
#4
Sounds like you might be able to do what we do in out TVCatchup addon to check when to update EPG data, (as long as your sleepTime is in minutes).

We have a python script that checks for an update and if necessary processes it.

Then the clever bit! Before the script exits it creates an alarm to go off 60 minutes later (in our case) which simply calls the same script passing in any necessary parameters (in your case this would just be sleepTime), note all the parameters have to be strings but I dont think this is a big deal.

The initial call can if you want be called via a service, the advantage of this is that the script can even be updated if your addon is still running.

i.e. In your service (I assume your sleeptime is 10 minutes, and the script is in a file called weather.py):

Code:
import weather
weather.doUpdate('10') #needs to be a string

then your weather.py would looks like this:

Code:
import xbmc
import os

def doUpdate(sleeptime):  
       try:
           #do some stuff that takes about 10 seconds
           print "[MeteoThread] fetching data complete, now sleeping "+sleeptime+" minutes"
       except:
           pass

       path   = ''              #Here you need the path to your script
       name   = 'WeatherUpdate' #Used to name Alarm so not important
       args   = sleeptime       #If more arguments necessary, remember to separate with a ','
       script = os.path.join(path, 'weather.py')
       cmd    = 'AlarmClock(%s,RunScript(%s,%s),%s,True)' % (name, script, args, sleeptime)    

       xbmc.executebuiltin(cmd)

if __name__ == '__main__':    
    doUpdate(sys.argv[1])

When xbmc exits there are no threads or sleeping processes to cleanup and it just exits gracefully. Genius eh!
Reply
#5
Used that but it's not always a solution
Read/follow the forum rules.
For troubleshooting and bug reporting, read this first
Interested in seeing some YouTube videos about Kodi? Go here and subscribe
Reply
#6
(2012-11-25, 20:42)Martijn Wrote: Used that but it's not always a solution

Even if we knew which suggestion you were referring to, this is not a particularly helpful comment.

Reply
#7
(2012-11-25, 20:59)spoyser Wrote:
(2012-11-25, 20:42)Martijn Wrote: Used that but it's not always a solution

Even if we knew which suggestion you were referring to, this is not a particularly helpful comment.

What?

I was responding to your example and it is exactly like I said. You cannot always use that
Read/follow the forum rules.
For troubleshooting and bug reporting, read this first
Interested in seeing some YouTube videos about Kodi? Go here and subscribe
Reply
#8
Well obviously it isn't the answer to all problems, but from what I can tell from the OP it is a perfectly good solution to the problem raised in the OP.

Hence my comment about your post being pointless.
Reply
#9
(2012-11-25, 21:18)spoyser Wrote: Well obviously it isn't the answer to all problems, but from what I can tell from the OP it is a perfectly good solution to the problem raised in the OP.

Hence my comment about your post being pointless.

What on earth makes it pointless for me to say that this not always the right solution?
Is warning him not a good enough reason even if it works it in this case.

But what do i know i guess......
Read/follow the forum rules.
For troubleshooting and bug reporting, read this first
Interested in seeing some YouTube videos about Kodi? Go here and subscribe
Reply
#10
I like the idea of using an xbmc timer for these kinds of updates, but if this is weather related.

I would create my own weather addon, that checks your weather station, then when done calls the weather.underground script for instance. that way no additional timers are running and your script does not have to continuously run.

one caveate to this method, is i believe for the weather to update the active window needs to have some weather infolabel in it.
For python coding questions first see http://mirrors.xbmc.org/docs/python-docs/
Reply
#11
(2012-11-25, 21:44)Nuka1195 Wrote: I like the idea of using an xbmc timer for these kinds of updates, but if this is weather related.

I would create my own weather addon, that checks your weather station, then when done calls the weather.underground script for instance. that way no additional timers are running and your script does not have to continuously run.

one caveate to this method, is i believe for the weather to update the active window needs to have some weather infolabel in it.

Carefull before he is gonna say this is useless too Wink
Read/follow the forum rules.
For troubleshooting and bug reporting, read this first
Interested in seeing some YouTube videos about Kodi? Go here and subscribe
Reply
#12
Well, I come back to this post and I am happy to see so much advice. Or even confused as there does not seem to be any perfect solution (is there ever any?)

(2012-11-25, 21:44)Nuka1195 Wrote: I would create my own weather addon, that checks your weather station, then when done calls the weather.underground script for instance. that way no additional timers are running and your script does not have to continuously run.
Actually the script evolved since the old post I referred to, as the script also checks for the status of the different automated backus I have put in place via rsync and display a summary on the main screen.

To minimze the effort on my side I'll try to go with Ronie's suggestion to shorten the loop while listenning to abortRequested and see how that goes.

I'll post the results.

V.

Reply
#13
Semi related, do xbmc's alarms consume cycles/ram while waiting? or does xbmc check to see "if there are any alarms set for this minute"?

Reason I ask is I have a service addon that checks a url every 5 minutes and pops a notification if something changes. I'm currently using xbmc.sleep(250) to and checking the current time against the target time. It seems like it would be more efficient to use alarms, but I haven't had a chance to test it out.
Reply
#14
Here is what I ended up doing (quick and dirty) : shorten the sleep cycles, but poll data only once in a while. The system is now much faster to stop.

V.

Code:
class MeteoThread (threading.Thread):
  
  def __init__(self, threadID, sleeptime):
    self.threadID = threadID
    self.sleeptime = sleeptime
    self.timeslept = float('inf')
    threading.Thread.__init__(self)
    self.setDaemon(True)
  
  def run(self):
    while 1==1:
      if self.timeslept>self.sleeptime:
        print "[MeteoThread] fetching data"
        .....
        print "[JCMeteoThread] fetching data complete (set #"+str(counter)+"), now sleeping..."
        self.timeslept = 0
      else :
        self.timeslept=self.timeslept+self.sleeptime/180
       time.sleep(self.sleeptime/180)

print "[Meteo] starting..."
HomeWindow = xbmcgui.Window( 10000 )
HomeWindow.setProperty( 'Meteo.counter' , str(0) )
pollingthread = MeteoThread(0, 60*30)
pollingthread.start()[/php]
print "[Meteo] started"
Reply

Logout Mark Read Team Forum Stats Members Help
Thread started within script prevents XBMC to close normally0