[MonoDevelop] Issues with the gui thread

Todd Berman tberman@off.net
Mon, 20 Sep 2004 16:28:03 -0700


On Mon, 2004-09-20 at 23:58 +0200, Lluis Sanchez wrote:
> Hi!
> 
> One of the problems I find when writing code for MonoDevelop is that the
> user interface can only be modified from the GUI thread. This means
> that, for example, if I have a background thread that needs to add
> something in the task pane, I need to do it through the DispatchService.
> 
> However, the fact that TaskService.AddTask (and many other methods)
> needs to run in the gui thread is common knowledge not documented
> anywhere, and even if it was documented, this information wouldn't be
> reliable. For example, the TaskService itself does not modify the user
> interface, but an OpenTaskView object is subscribed to the TaskAdded
> event, and that one changes de UI. This makes the development of plugins
> really hard.
> 
> In order to simplify the development and to make MonoDevelop more stable
> I think we should stablish a policy like "any public class that can be
> used by a plugin must be gui-thread safe" that is, no matter from which
> thread a method is called, it should do its work, internally dispatching
> the call through the DispatchService if needed.
> 
> Following this rule, the TaskService.AddTask method would not need to do
> anything special, since it does not directly modify the gui, but
> OpenTaskView would need to internally dispatch the TaskAdded event
> through the DispatchService.
> 
> To simplify even more the development I propose to build two artifacts:
> 
>       * Provide a base class for classes that need access to the GUI.
>         All method calls to objects of that class would be automatically
>         marshalled and executed in the gui thread. This can be
>         implemented using ContextBoundObject and the interception sinks
>         it provides. This would be really useful for example to make the
>         status bar service thread safe by only changing the base class. 
> 
>       * Provide a method for building wrapper delegates that would
>         automatically marshall calls into the gui thread, so I could do
>         something like:
> 
>         taskService.TasksChanged +=
>         (EventHandler)DispatchService.CreateGuiDispatch (new
>         EventHandler (ShowResults));
>         
>         This would generate a wrapper delegate that would queue the call
>         into the gui thread. This would need some Reflection.Emit, but
>         not too much.
>         
> Of course, we could still use the traditional DispatchService methods,
> but I think that those "artifacts" would be enough for most of
> situations.
> 

Yes. That sounds perfect.

We had begun to implement some stuff similar to that (Where public API
was considered to be safe regardless of where it was called from), but
didn't get anywhere near completion.

One thing to keep in mind, is some code will potentially have to be
restructured.

When you dispatch something to the gui thread, you get execution back
right away, potentially before the code has done what you needed it to
do.

Case in point:

When you double click on a method node in the class browser, it was
calling OpenFile. OpenFile was changed to internally use
DispatchService. However, the rest of the code in the event handler
inside the class browser continued to run, and it attempted to operate
on the 'newly' opened window, that wasn't actually open. These sorts of
changes have to be watched for. Also, we are opening ourselves up to a
very difficult to debug situation. While I agree that this is absolutely
the right direction, debugging this new code will be far more difficult,
as you wont get a stack trace beyond the most recent gui thread
transition.

--Todd