(Un) Managed mysteries
11 Jul 2005 » permalink
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.