11.Jul.2005
So I started to bind my unamanged C code to managed C# code (the GUI of Diva will be written in mono). I was expecting problems at this stage – my unmanaged libGdv is dynamically linked against other shared objects (GStreamer) and I didn’t really know what to expect. But it all turned out smoothly, working just “out of the box”. Thanks to GObject, wrapping all the properties/constructors is a charm. It seems I can completely skip gst-sharp – all the required GStreamer code is encapsulated by my library.
A single serious issue I ran into was related to threads (of course). libGdv is heavily multi-threaded to smothly handle the playback, asynchronously generate frame thumbnails, etc. The main application (managed code) doesn’t need to know much about the threads. Though, the threads need to send periodic notifications about the playback state so that managed can update the GUI.
The essence of the problem: unmanaged threads need to enter the managed code. The straight approach (passing pointers to delegates) obviously doesn’t work here (garbage collecting). There is some of material how this functionality can be achieved, but I found a pretty nifty solution:
g_idle_add
In your unmanaged thread you just g_idle_add the pointer to the managed delegate, and it gets called-back by your main g_loop thread later on. Before that, you need to start the g_loop in the managed (Application.Init ()). That solves my problems perfectly, as the notifications might come from different threads (audio, video…) but only one thread is to process them.
I made a simple example to demonstrate the concept – a threaded counter.
It’s a smallish gtk app written in C# – counts seconds. The counter code lives in a C shared library and is executed as a separate thread. This unmanaged code fires periodic notifications that are catched by the managed C# and used to update the GUI.
ThreadedCounter.tar.gz – C/C# source with a Makefile.
Powered by Mephisto with a micro theme mod
1 Comment
Cool! Another solution would be to have the thread fire an event in your unmanaged code, which propagates into your managed code, and is added to an event queue. In your main thread, listen for additions to the queue, and respond to the events. You can also wrap UI code in threads with Gdk.Threads.Enter() and Gdk.Threads.Leave().
I have a Core class which sets up and provides a quick path into a lot of the core elements of Sonance. This is often very helpful:
public class Core { private System.Threading.Thread MainThread;
}
You might find something like that useful as you delve into the intricacies smooth, responsive UI design. Keep up the great work!
Sorry, comments are closed for this article.