Skip to content
This repository has been archived by the owner on Oct 1, 2024. It is now read-only.

Synchronization context doesn't seem to exist, breaking async/await by default. #293

Open
sonicmouse opened this issue Mar 7, 2021 · 7 comments

Comments

@sonicmouse
Copy link

sonicmouse commented Mar 7, 2021

I posted this question on Stack Overflow a while ago, and nobody responded -- so I decided I am going to go right to the source because I am very curious to know why things are the way they are.

I am using MonoDevelop with GTK Sharp 2.12. I have set this up using the default GTK Sharp windowed project. Add a button, add a button-click event and placed the following code:

protected async void OnBtnTest(object sender, EventArgs e)
{
	Debug.WriteLine($"Before: {Thread.CurrentThread.ManagedThreadId}");

	await Task.Delay(2000);

	Debug.WriteLine($"After: {Thread.CurrentThread.ManagedThreadId}");

	using (var msg = new MessageDialog(this, DialogFlags.Modal,
	    MessageType.Info, ButtonsType.Ok, "CRASH"))
	{
		msg.Run();
		msg.Destroy();
	}
}

The output is:

Before: 1
Started Thread 27672
After: 4

(TestSyncContext:26912): Gdk-CRITICAL **: gdk_window_set_geometry_hints: assertion 'GDK_IS_WINDOW (window)' failed

The "critical" line is a crash in the program -- This is because the UI thread didn't return when continuing on to show the MessageDialog. You can see the managed thread ID changed after the call to await.

Puzzled by this, I started researching and found this bit of code from a long, long time ago; Specifically these lines caught my attention:

gtk_init (ref argc, ref argv);
SynchronizationContext.SetSynchronizationContext (new GLib.GLibSynchronizationContext ());

So I started to wonder: Does GTK Sharp not set up a synchronization context by default?

I decided to throw it in the code, but GLib.GLibSynchronizationContext() does not exist in the GLib library.

OK, that's odd -- I searched for that on the web and found the source code to that object; Copied and pasted it in to my project, then called it as so:

class MainClass
{
    public static void Main(string[] args)
    {
        Application.Init();
        SynchronizationContext.SetSynchronizationContext(new GLibSynchronizationContext());

        MainWindow win = new MainWindow();
        win.Show();
        Application.Run();
    }
}

Ran it again, and it performs how I would have expected it to without adding a context:

Before: 1
Started Thread 22744
After: 1

No crashes. UI thread came back to continue on down the method.

My questions are:

  1. Did GTK Sharp intentionally not include a synchronization context in their UI framework on purpose?
  2. Did GTK Sharp intentionally not attempt to initialize a sync-ctx on purpose? Meaning they never intended it to work with the async/await pattern by default?
  3. Why is GLib.GLibSynchronizationContext no longer available?
  4. Is what I did to fix it the correct way to add a proper sync-ctx to GTK Sharp?

I have production code with this fix going out, and I want to make sure that what I did isn't unorthodox. OR: maybe there is a better way to set up GTK Sharp to handle the async/await pattern that isn't very well documented.

(BTW, I shipped the code as it is above with the make-shift sync-ctx and it's running on thousands of clients with no issues, still interested in some sort of explanation.)

@decriptor
Copy link
Contributor

I'm not sure about the GlibSynchronizationContext, but my assumption is that the need for one comes long after any real active development. Here is one that the monodevelop team wrote however. https://github.com/mono/monodevelop/blob/fb12ccb7f4245eca20803661deaa37ead0ec35af/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/DispatchService.cs#L48

@decriptor
Copy link
Contributor

@Therzok could give a much better answer.

@Therzok
Copy link
Contributor

Therzok commented Mar 8, 2021

I don't think GTK# 2.12 had code written for it to use SynchronizationContext. It's probably way easier to copy the MonoDevelop one that @decriptor linked.

@decriptor
Copy link
Contributor

decriptor commented Mar 8, 2021

@Therzok Would it be worth "porting" that one over to GTK# 2.12 and just including it?

@Therzok
Copy link
Contributor

Therzok commented Mar 13, 2021

That means handling a new release of gtk#, which I don't know how to do. Copying it since it already exists in the codebase is an easy workaround.

@meebey
Copy link
Contributor

meebey commented Mar 14, 2021 via email

@sonicmouse
Copy link
Author

Just an update: Using this synchronization context code, I pushed out an update to thousands of machines in a production environment and there have been no issues. The software is running on Linux (Ubuntu 18.04) and Windows (Win7 and Win10) with absolutely no issues to report.

So if there is anyone out there on the fence about using a synchronization context with GTK-Sharp 2.12, you may be in luck using the aforementioned code.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants