www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Threading to prevent GUI Freeze

reply TheDGuy <loder.feuer googlemail.com> writes:
Hello,

i use GTKD to draw some stuff on a DrawingArea. Because it needs 
some time to calculate i want to outsource those calculation so 
that the GUI doesn't freeze.

I tried it with "std.concurrency" like this:

bool drawCallback(Scoped!Context cr, Widget widget){
	writeln("init");
	spawn(&render, cr, widget);
	return true;
}

void render(Context cr, Widget widget){
	Renderer renderer = new Renderer(new Vector3D(0,0,0), cr, 
widget);
	int  i = 0;
	while(i < 4){
		renderer.renderOneStep();
		i++;
	}
	renderer.DisplayResult();
}

But i get:

"std.concurrency.spawn(F, T...)(F fn, T args) 
if(isSpawnable!(F,T))"
"Error: template std.concurrency.spawn cannot deduce function 
from argument types!()(void delegate(Context cr, Widget widget), 
Scoped Widget), candidates are:"
Jan 04
next sibling parent reply Luis <luis.panadero gmail.com> writes:
On Monday, 4 January 2016 at 14:31:04 UTC, TheDGuy wrote:
 Hello,

 i use GTKD to draw some stuff on a DrawingArea. Because it 
 needs some time to calculate i want to outsource those 
 calculation so that the GUI doesn't freeze.

 I tried it with "std.concurrency" like this:

 bool drawCallback(Scoped!Context cr, Widget widget){
 	writeln("init");
 	spawn(&render, cr, widget);
 	return true;
 }

 void render(Context cr, Widget widget){
 	Renderer renderer = new Renderer(new Vector3D(0,0,0), cr, 
 widget);
 	int  i = 0;
 	while(i < 4){
 		renderer.renderOneStep();
 		i++;
 	}
 	renderer.DisplayResult();
 }

 But i get:

 "std.concurrency.spawn(F, T...)(F fn, T args) 
 if(isSpawnable!(F,T))"
 "Error: template std.concurrency.spawn cannot deduce function 
 from argument types!()(void delegate(Context cr, Widget 
 widget), Scoped Widget), candidates are:"
Before doing anything with threads and GTK, you should read this : http://blogs.operationaldynamics.com/andrew/software/gnome-desktop/gtk-thread-awareness
Jan 04
parent reply TheDGuy <loder.feuer googlemail.com> writes:
On Monday, 4 January 2016 at 15:07:12 UTC, Luis wrote:
 On Monday, 4 January 2016 at 14:31:04 UTC, TheDGuy wrote:
 [...]
Before doing anything with threads and GTK, you should read this : http://blogs.operationaldynamics.com/andrew/software/gnome-desktop/gtk-thread-awareness
Okay, so i have to do it like this on every function i use from GTKD? threadsInit(); threadsEnter(); GtkAllocation size; widget.getAllocation(size); threadsLeave();
Jan 04
parent reply Gerald <me me.com> writes:
On Monday, 4 January 2016 at 15:28:56 UTC, TheDGuy wrote:
 On Monday, 4 January 2016 at 15:07:12 UTC, Luis wrote:
 On Monday, 4 January 2016 at 14:31:04 UTC, TheDGuy wrote:
 [...]
Before doing anything with threads and GTK, you should read this : http://blogs.operationaldynamics.com/andrew/software/gnome-desktop/gtk-thread-awareness
Okay, so i have to do it like this on every function i use from GTKD? threadsInit(); threadsEnter(); GtkAllocation size; widget.getAllocation(size); threadsLeave();
I wrote a demo for GtkD showing how multi-threading and D work together, it's in the demos/gtkD/DemoMultithread folder of GtkD, hopefully it will be helpful. However this example it is based on using the GTk threadIdle callback which is generally preferred over the locking methods you show above, obviously though your use case may vary but keep in mind the locking methods have been deprecated, see the GTK 3 reference manual here: https://developer.gnome.org/gdk3/stable/gdk3-Threads.html You also see this GtkD issue here for https://github.com/gtkd-developers/GtkD/issues/137 for some code on how to use Delgates with gdk_threads_add_idle (i.e. GtkD gdk.Threads.threadsAddIdle).
Jan 04
parent reply TheDGuy <loder.feuer googlemail.com> writes:
 I wrote a demo for GtkD showing how multi-threading and D work 
 together, it's in the demos/gtkD/DemoMultithread folder of 
 GtkD, hopefully it will be helpful. However this example it is 
 based on using the GTk threadIdle callback which is generally 
 preferred over the locking methods you show above, obviously 
 though your use case may vary but keep in mind the locking 
 methods have been deprecated, see the GTK 3 reference manual 
 here:

 https://developer.gnome.org/gdk3/stable/gdk3-Threads.html

 You also see this GtkD issue here for 
 https://github.com/gtkd-developers/GtkD/issues/137 for some 
 code on how to use Delgates with gdk_threads_add_idle (i.e. 
 GtkD gdk.Threads.threadsAddIdle).
Thanks for your example code. Do i need those extern (C) function? Why is it not possible to write the value to the TreeView in D?
Jan 04
parent reply Gerald <me me.com> writes:
On Monday, 4 January 2016 at 16:13:50 UTC, TheDGuy wrote:
 Thanks for your example code. Do i need those extern (C) 
 function?
Yes, you need it. The extern (C) function is what GDK invokes on idle. In any GUI application there is a lot of idle time waiting for events, what the addThreadIdle allows you to do is take advantage of this and tell GTK that whenever it's sitting around doing nothing, give this function a call. The idea is that you spawn a thread that does your work and when GTK invokes your thread idle callback where you can check the status of the thread and update the UI accordingly. For example, let's say you need to render a highly complicated graph that takes a few minutes to complete. You could spawn a thread that renders it into an off-line buffer of some sort and once completed sends a message to the GTK main thread using std.concurrency. At some point GTK calls your thread idle callback and you simply invoke the std.concurrency.receive and see a message saying the graph has been rendered is available, and if so, copy it into the appropriate GTK widget. The important thing to understand is that the thread idle callback happens in the GTK main thread so it is completely safe to update GTK widgets from here. The other thing to understand is that whatever you work you do in the callback must be short, if you don't return in a reasonable amount of time you are blocking the main GTK thread. As a result it really should only be used as a mechanism to track work progress in whatever threads you have spawned. The GTK thread idle callback works beautifully with D's std.concurrency send and receive mechanism. Note the code I pointed you to in that D github Issue abstracts the extern (C) function from you and allows you to use normal D delegates as callbacks. The issue was created to get this incorporated into GtkD as I agree the framework should abstract this.
 Why is it not possible to write the value to the TreeView in D?
I don't understand what you mean as of course it's possible to update value's in a TreeView. Do you mean why am I updating it from the callback (i.e. the C function)? The code here is an artificial example where it is simply updating the treeview with an iterating number generated in a separate thread. The results being posted to the TreeView could just as easily be a resultset from a long running database query, a complicated mathematical expression, etc. Hopefully the previous explanation helps you understand what the callback is doing. You can see a more real world example of GtkD multi-threading in this application I wrote called Visual Grep (https://github.com/gnunn1/vgrep), it puts a GTK GUI around grep with all searches running in background threads and updating Gtk TreeView as results come in. It also uses the delegate code linked in that issue which originally came from an application called grestful. Note Visual Grep was my first ever D/GtkD program so there is some ugh code in there, but hopefully it can act as an additional source of info for you.
Jan 04
parent reply TheDGuy <loder.feuer googlemail.com> writes:
On Monday, 4 January 2016 at 17:33:28 UTC, Gerald wrote:
 On Monday, 4 January 2016 at 16:13:50 UTC, TheDGuy wrote:
 [...]
Yes, you need it. The extern (C) function is what GDK invokes on idle. In any GUI application there is a lot of idle time waiting for events, what the addThreadIdle allows you to do is take advantage of this and tell GTK that whenever it's sitting around doing nothing, give this function a call. [...]
Okay, thanks alot for your help. I think i will need some time to understand this but one last question: Do the errors come from the fact at i didn't use those GTK thread mechanisms or that my function is not "spawnable"? "std.concurrency.spawn(F, T...)(F fn, T args) if(isSpawnable!(F,T))" "Error: template std.concurrency.spawn cannot deduce function from argument types!()(void delegate(Context cr, Widget widget), Scoped Widget), candidates are:"
Jan 04
parent Gerald <me me.com> writes:
On Monday, 4 January 2016 at 18:04:34 UTC, TheDGuy wrote:
 On Monday, 4 January 2016 at 17:33:28 UTC, Gerald wrote:
 On Monday, 4 January 2016 at 16:13:50 UTC, TheDGuy wrote:
 [...]
Yes, you need it. The extern (C) function is what GDK invokes on idle. In any GUI application there is a lot of idle time waiting for events, what the addThreadIdle allows you to do is take advantage of this and tell GTK that whenever it's sitting around doing nothing, give this function a call. [...]
Okay, thanks alot for your help. I think i will need some time to understand this but one last question: Do the errors come from the fact at i didn't use those GTK thread mechanisms or that my function is not "spawnable"? "std.concurrency.spawn(F, T...)(F fn, T args) if(isSpawnable!(F,T))" "Error: template std.concurrency.spawn cannot deduce function from argument types!()(void delegate(Context cr, Widget widget), Scoped Widget), candidates are:"
Keep in mind I know nothing about Cairo and I don't have time to try your code, but what happens if you remove the Scoped template from the Context parameter? Also, have you checked if Cairo is thread-safe the way you are using it in the spawned function? I'm not sure if Cairo has the same restrictions that GTK widgets do.
Jan 04
prev sibling parent =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 01/04/2016 06:31 AM, TheDGuy wrote:

 I tried it with "std.concurrency" like this:

 bool drawCallback(Scoped!Context cr, Widget widget){
      writeln("init");
      spawn(&render, cr, widget);
The first parameter to render() is Scoped!Context but render() takes a Context:
 void render(Context cr, Widget widget){
Unless there is implicit conversion from Scoped!Context to Context, it won't work. Perhaps you need to call an accessor like the following? spawn(&render, cr.some_accessor(), widget); Ali
Jan 04