Author Topic: Ouch, threading...  (Read 9300 times)

Elberet

  • Full Member
  • ***
  • Posts: 167
I'm going to post this hoping that it'll help others avoid my stupid blunders... and hoping that Steven might have a bright idea how plugins can be shielded from this complexity.

What I did:
- For debugging, print each received notificatio to a small window.
- The window runs on MusicBee's main thread.
- Messages are printed by Invoke'ing the textbox control (owned by the main thread).
- I prevented the plugin from running entry points (PluginClosed, NotificationReceived, etc.) concurrently.
Sounds innocent enough, right?

Here's what happens:
- MusicBee gets quit, which gets handled on the main thread.
- MB stops the auto Dj which results in a notification on a separate thread.
- On the worker thread, plugin tries to Invoke a control on the main thread, and Invoke locks.
- Back on the main thread, MB tries to run PluginClosed on the plugin, which conflicts with the blocking Invoke above and deadlocks.
- Alternatively, without the explicit locks, MB finishes shutting down; but when the main thread is free to handle the still waiting Invoke, the control that was originally invoked is now disposed and the invoking thread is thrown an exception.

So, what to do, what to do. In my case, I'll use an asynchronous BeginInvoke and catch the exception, but plugins that want to do some legitimate GUI work might run into problems here. How about if disposing the main window is delayed until plugins have finished closing on their worker thread? That way, the GUI thread could be freed up for plugins to do some last-minute user interaction.

Steven

  • Administrator
  • Sr. Member
  • *****
  • Posts: 34349
Here's what happens:
- MusicBee gets quit, which gets handled on the main thread.
- MB stops the auto Dj which results in a notification on a separate thread.
- On the worker thread, plugin tries to Invoke a control on the main thread, and Invoke locks.
this bit here, if you have already told MB to quit, why would you try to Invoke back to the MB GUI thread? it would be in an unpredictable state.
If you did need to something to the MB GUI thread, wouldnt the time to do it just before you request MB to quit

i dont have the code in front of me now, but i would think that on recieving the quit message MB sends a Stop AutoDJ message on the plugin thread (which perhaps should not be sent at all if the application is closing because of timing issues), then from the main GUI thread it calls Close() on the plugin

Elberet

  • Full Member
  • ***
  • Posts: 167
Oh sorry, that didn't come out clear. By "told to quit" I meant "clicked the X button on MusicBee's main window", the point being that MusicBee is quitting due to a user-generated event, which a plugin may want to respond to in some way.

on recieving the quit message MB sends a Stop AutoDJ message on the plugin thread (which perhaps should not be sent at all if the application is closing because of timing issues)
Timing is one issue, another is that while a plugin is receiving notifications, it should not have to worry about MusicBee possibly being in a weird state, such as the middle of shutting down.

Steven

  • Administrator
  • Sr. Member
  • *****
  • Posts: 34349
i've changed it so if shutdown has started it wont post any messages to the plugin ie. you wont get the autodj stop message. MB will just call the Close() function on the main GUI thread as its doing now.

http://www.mediafire.com/?fb7813o3qzgh4jl
Last Edit: June 23, 2011, 06:41:56 AM by Steven

Elberet

  • Full Member
  • ***
  • Posts: 167
Alright. Would it be safe(ish) to run the message pump manually while doing more stuff in a background thread? Is MusicBee locked on any Monitors or waiting on any threads or wait handles while Close() runs?