Monitor.onNotification, xbmc.sleep/xbmc.waitForAbort and multi-threading
#1
My screensaver script has numerous threads and uses several Monitor subclasses. After some testing it appears that your code won't receive a Monitor.onNotification unless xbmc.sleep/xbmc.waitForAbort is called from the same thread that the Monitor was instantiated from. I also noticed that if I had multiple monitors I could get the same notification as soon as each thread called xbmc.sleep. I have tried to find where this behavior has been documented without any success. Is this a well-known behavior?

Also, while I try to have the code call xbmc.waitForAbort whenever a wait/sleep is  needed, you can not avoid using Python waits as well. For situations where a long wait is possible, I try to use threading.Event, and then when an Abort occurs, call threading.Event().set() so that anything waiting are aborted early.

If the monitoring is behaving as I believe, then I think I will change to  have the main thread to:
  • Own all of the monitors
  • Be pretty simple
  • Spend most of it's time sleeping
  • Any expensive operations will be spun off onto independent threads.
Does this sound reasonable?  Does anyone know Kodi's Python thread model?
  1. Is there a single thread to notify all plugins of a monitored event?
  2. How important is it to avoid taking too long to process some notification from Kodi?
Thanks for  any insights.

Frank
Reply
#2
Well, first off, Kodi 18 brings some pretty big changes to table for this exact situation.
In Kodi 17, you had to be extra careful that your main thread does not exit, or Kodi will instantly dispose all extra threads and the whole Python instance.
In Kodi 18, supposedly this is not the case, as the Python instance is recycled to make better use of caching and avoid the overhead of creating the Python instance every time.

As for specifics to your particular issue, I'm not sure, but I've definitely done my share of wrangling with disposed and isolated instances, which may affect your experience.
Developer for Shoko and Nakamori. Long time user of Kodi, before it was even called Kodi. My XBOX died long ago, but Windows is still just as broken and necessary. I obviously watch anime, given my first comment. Video games, manga, music, you name it.
Reply
#3
No idea why one would want to cram all this complexity into limited kodi addons instead of making a SaaS.
Reply
#4
Because making a service as hardware and OS agnostic as Kodi isn't easy. It's not like it needs to run in the background forever either, just while Kodi is running. That's my two cents on why, but it doesn't help the OP any more than you did.
Developer for Shoko and Nakamori. Long time user of Kodi, before it was even called Kodi. My XBOX died long ago, but Windows is still just as broken and necessary. I obviously watch anime, given my first comment. Video games, manga, music, you name it.
Reply
#5
(2019-03-24, 22:22)fbacher Wrote: Thanks for  any insights.
  

For what its worth (I'm also trying to write my first kodi addon) when I've looked at mature addons your suggestion is how most are operating. Take as an example the trakt addon source code. The main operation only has the following:

 
python:

startup_delay = kodiUtilities.getSettingAsInt('startup_delay')
if startup_delay:
logger.debug("Delaying startup by %d seconds." % startup_delay)
xbmc.sleep(startup_delay * 1000)

logger.debug("Service thread starting.")

# purge queue before doing anything
self.dispatchQueue.purge()

# setup event driven classes
self.Player = traktPlayer(action=self._dispatchQueue)
self.Monitor = traktMonitor(action=self._dispatchQueue)

# init traktapi class
globals.traktapi = traktAPI()

# init sync thread
self.syncThread = syncThread()

# init scrobbler class
self.scrobbler = Scrobbler(globals.traktapi)

AddonSignals.registerSlot('service.nextup.notification', 'NEXTUPWATCHEDSIGNAL', self.callback)

# start loop for events
while not self.Monitor.abortRequested():
while len(self.dispatchQueue) and (not self.Monitor.abortRequested()):
data = self.dispatchQueue.get()
logger.debug("Queued dispatch: %s" % data)
self._dispatch(data)

if xbmc.Player().isPlayingVideo():
self.scrobbler.transitionCheck()

if self.Monitor.waitForAbort(1):
# Abort was requested while waiting. We should exit
break

# we are shutting down
logger.debug("Beginning shut down.")

# delete player/monitor
del self.Player
del self.Monitor

# check if sync thread is running, if so, join it.
if self.syncThread.isAlive():
self.syncThread.join()

Hope that helps
Reply

Logout Mark Read Team Forum Stats Members Help
Monitor.onNotification, xbmc.sleep/xbmc.waitForAbort and multi-threading0