Terminal.Gui icon indicating copy to clipboard operation
Terminal.Gui copied to clipboard

Add article on threading

Open tznind opened this issue 3 years ago • 5 comments

Often we encounter users who are using Threads but do not know about Application.MainLoop.Invoke. For example:

Yes every one sec I have to use the same frameView with new data.

https://github.com/gui-cs/Terminal.Gui/issues/2562#issuecomment-1514559020

I have created an article to explain how to update main UI thread from a background task.

Note that this targets develop so current users should see it. We can cherry pick it into v2_develop

Pull Request checklist:

  • [ ] I've named my PR in the form of "Fixes #issue. Terse description."
  • [ ] My code follows the style guidelines of Terminal.Gui - if you use Visual Studio, hit CTRL-K-D to automatically reformat your files before committing.
  • [ ] My code follows the Terminal.Gui library design guidelines
  • [ ] I ran dotnet test before commit
  • [ ] I have made corresponding changes to the API documentation (using /// style comments)
  • [ ] My changes generate no new warnings
  • [ ] I have checked my code and corrected any poor grammar or misspellings
  • [ ] I conducted basic QA to assure all features are working

tznind avatar Apr 21 '23 07:04 tznind

I see though that there is a section in mainloop.md but I think its worthy to be its own article since it is so common to see this issue.

tznind avatar Apr 21 '23 08:04 tznind

This has been on the docs for a very long time:

https://github.com/gui-cs/Terminal.Gui/blob/develop/docfx/articles/mainloop.md#threading

Oh, I see your second comment now.

Yeah, might make sense to give it more visibility, given this

migueldeicaza avatar Apr 22 '23 02:04 migueldeicaza

I guess it's worth mentioning that Termital.Gui has it's own SynchronizationContext and it really depends on how this task is started.

(Note: SynchronizationContext is just an abstraction over some kind of Scheduler. In case of Terminal.Gui it's a single UI thread message loop)

Few examples with default System.Threading.Task:

Button clicked by user
 -> Processed by UI thread
 -> Has SynchronizationContext
 -> SomeAsyncMethodCalled with no ConfigureAwait(false)
 -> Some awaits inside
 -> Always jump back to UI's thread SynchronizationContext when await is done
 -> UI updates are valid

In this case some Task is started from UI thread and SynchronizationContext is saved so technically it's not background.
Button clicked by user
 -> Processed by UI thread
 -> Has SynchronizationContext
 -> SomeAsyncMethodCalled with ConfigureAwait(false)
 -> Some awaits inside
 -> Always jump to thread pool because ConfigureAwait(false) makes it ignore SynchronizationContext
 -> UI updates are invalid

In this case some Task is started from UI thread but SynchronizationContext is not saved so technically it's background.
Some work started with Task.Run
 -> Processed by ThreadPool thread
 -> No SynchronizationContext
 -> ...
 -> UI updates are invalid

This case is quite straight: no SynchronizationContext from the start because it's queued directly on ThreadPool

Examples above show that the problem is that when using async machinery you can't always be sure whether you are on UI thread or not.

Possible means to fix this:

  1. Do every UI update via Appication.MainLoop (like in the doc) if you're not sure code is running on UI thread after an await.
  2. (My favorite) Just write a custom Task that will always run on UI thread via Mainloop.Invoke and run every async UI update using this custom Task. This is very similar to 1) but is done automatically

I hope this helps someone understand it better

En3Tho avatar May 07 '23 11:05 En3Tho

@tznind did you see my change request?

tig avatar May 10 '23 04:05 tig

Yeah sorry, not had a chance to get back to this yet. Its on my todo list.

On Wed, 10 May 2023, 05:33 Tig, @.***> wrote:

@tznind https://github.com/tznind did you see my change request?

— Reply to this email directly, view it on GitHub https://github.com/gui-cs/Terminal.Gui/pull/2568#issuecomment-1541338272, or unsubscribe https://github.com/notifications/unsubscribe-auth/AHO3C5AAU2R5GWAP5QKXCQDXFMK7ZANCNFSM6AAAAAAXGQ5BNU . You are receiving this because you were mentioned.Message ID: @.***>

tznind avatar May 10 '23 05:05 tznind