Bug 57544 - Linux: BackgroundWorker ProgressChanged and RunWorkerCompleted not executed in correct thread
Summary: Linux: BackgroundWorker ProgressChanged and RunWorkerCompleted not executed i...
Status: CONFIRMED
Alias: None
Product: Gtk#
Classification: Mono
Component: gtk-sharp ()
Version: 2.x
Hardware: PC Linux
: --- normal
Target Milestone: ---
Assignee: Bugzilla
URL:
Depends on:
Blocks:
 
Reported: 2017-06-16 05:58 UTC by xamarin
Modified: 2017-06-21 14:43 UTC (History)
3 users (show)

Tags:
Is this bug a regression?: ---
Last known good build:

Notice (2018-05-24): bugzilla.xamarin.com is now in read-only mode.

Please join us on Visual Studio Developer Community and in the Xamarin and Mono organizations on GitHub to continue tracking issues. Bugzilla will remain available for reference in read-only mode. We will continue to work on open Bugzilla bugs, copy them to the new locations as needed for follow-up, and add the new items under Related Links.

Our sincere thanks to everyone who has contributed on this bug tracker over the years. Thanks also for your understanding as we make these adjustments and improvements for the future.


Please create a new report for Bug 57544 on GitHub or Developer Community if you have new information to add and do not yet see a matching new report.

If the latest results still closely match this report, you can use the original description:

  • Export the original title and description: GitHub Markdown or Developer Community HTML
  • Copy the title and description into the new report. Adjust them to be up-to-date if needed.
  • Add your new information.

In special cases on GitHub you might also want the comments: GitHub Markdown with public comments

Related Links:
Status:
CONFIRMED

Description xamarin 2017-06-16 05:58:39 UTC
Description of Problem:
BackgroundWorker progress and completion events are NOT called on correct threads.

Steps to reproduce the problem:
1. Create BackgroundWorker on main thread with event handlers
2. Start it


Actual Results:
Progress and completion event handlers are called on threadpool threads.

Expected Results:
Progress and completion event handlers should be called on main (UI) thread when worker created and started on UI thread.

How often does this happen? 
Always

Additional Information:
Version 5.10
Installation UUID: 34e7037c-bfa4-44c3-b92a-cab81ac3fdbf
Runtime:
	Mono 5.0.1.1 (2017-02/5077205 Thu May 25 09:19:18 UTC 2017) (64-bit)
	GTK+ 2.24.30 (Ambiance theme)

Build Information
Build information unavailable

Operating System
Linux
Linux ubuntu 4.8.0-54-generic #57~16.04.1-Ubuntu SMP Wed May 24 16:22:28 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux


---

Here's the main part of the program (modified HelloWorldGtk):
-----
using System;
using Gtk;
using System.ComponentModel;
using System.Threading;

namespace HelloWorldGtk
{
	class MainClass
	{
		public static void Main (string[] args)
		{
			Application.Init ();
			MainWindow win = new MainWindow ();
			win.Show ();
			GLib.Idle.Add (StartTask);
			Application.Run ();
		}

		private static bool StartTask()
		{
			System.Diagnostics.Debug.WriteLine("CREATE: " + Thread.CurrentThread.ManagedThreadId);
			var worker = new BackgroundWorker ();
			worker.WorkerReportsProgress = true;
			worker.DoWork += Worker_DoWork;
			worker.ProgressChanged += Worker_ProgressChanged;
			worker.RunWorkerCompleted += Worker_RunWorkerCompleted;
			worker.RunWorkerAsync (worker);
			return false;
		}

		private static void Worker_RunWorkerCompleted (object sender, RunWorkerCompletedEventArgs e)
		{
			System.Diagnostics.Debug.WriteLine("COMPLETE: " + Thread.CurrentThread.ManagedThreadId);
		}

		private static void Worker_ProgressChanged (object sender, ProgressChangedEventArgs e)
		{
			System.Diagnostics.Debug.WriteLine ("PROGRESS!: " + Thread.CurrentThread.ManagedThreadId);
		}

		private static void Worker_DoWork (object sender, DoWorkEventArgs e)
		{
			System.Diagnostics.Debug.WriteLine ("DOING WORK: " + Thread.CurrentThread.ManagedThreadId);
			Thread.Sleep (1000);
			var worker = e.Argument as BackgroundWorker;
			worker.ReportProgress (50);
			Thread.Sleep (1000);
			worker.ReportProgress (100);
		}
	}
}
Comment 1 xamarin 2017-06-16 06:07:35 UTC
UPDATE: I have some old notes in source code elsewhere (written in MonoMac -- not tested in Xamarin.Mac) that indicate the same problem may exist in MonoMac. That code was written back in 2014 - things have changed a bit since then.

The codebase using BackgroundWorker *ALWAYS* creates the objects in the UI thread.
Comment 2 Vsevolod Kukol 2017-06-21 07:21:27 UTC
The BackgroundWorker needs a valid SynchronizationContext to synchronize with the UI thread, but Gtk# 2 does not register its own context (this has been added for Gtk# 3 only: https://github.com/mono/gtk-sharp/commit/8e07e7d2257b185866dedfda9cbf32b2e00cd3ee). You could create your own GLibSynchronizationContext, or use a different synchronization technique (i.e. synchronize manually with Gtk.Application.Invoke inside your handlers)
Comment 3 xamarin 2017-06-21 14:43:02 UTC
Ah OK -- thanks for the confirmation. I'd already implemented the Application.Invoke workaround in my abstraction layer. :D

When I circle back round to MonoMac/Xamarin.Mac testing of my app, I'll check / confirm behaviors there.