gtk-sharp icon indicating copy to clipboard operation
gtk-sharp copied to clipboard

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

Open sonicmouse opened this issue 3 years ago • 7 comments

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.)

sonicmouse avatar Mar 07 '21 07:03 sonicmouse

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 avatar Mar 07 '21 18:03 decriptor

@Therzok could give a much better answer.

decriptor avatar Mar 07 '21 18:03 decriptor

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.

Therzok avatar Mar 08 '21 14:03 Therzok

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

decriptor avatar Mar 08 '21 15:03 decriptor

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.

Therzok avatar Mar 13 '21 20:03 Therzok

If you need help doing gtk# releases for Linux, I am happy to help out as Smuxi heavily relies on this library and I am maintaining gtk# in Debian anyway...

--

On Sun, 14 Mar 2021, 04:29 Marius Ungureanu, @.***> wrote:

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.

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/mono/gtk-sharp/issues/293#issuecomment-798780826, or unsubscribe https://github.com/notifications/unsubscribe-auth/AACNU4WWMBV7VN4TADIXERLTDPDMJANCNFSM4YXSSRSA .

meebey avatar Mar 14 '21 01:03 meebey

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.

sonicmouse avatar Apr 29 '21 15:04 sonicmouse