GNOME Bugzilla – Bug 672094
Vala fails to initialize lock before first usage
Last modified: 2014-06-27 19:47:52 UTC
To see the problem, run the following program: === class Foo { static Foo instance = null; public static Foo get_instance() { lock (instance) { if (instance == null) instance = new Foo(); } return instance; } } int thread_func() { stdout.puts("thread started\n"); Foo.get_instance(); stdout.puts("thread exiting\n"); return 0; } void main() { try { for (int i = 0; i < 5 ; ++i) Thread.create<int>(thread_func, false); } catch (ThreadError e) { error(e.message); } Thread.usleep(10000000); } === On my 4-core machine (running Vala 0.15.2 and Ubuntu 12.04), the program's output typically looks like this: === thread started thread started thread started thread started thread started thread exiting === One or more threads successfully complete execution, but one or more threads remain deadlocked in the lock statement, unexpectedly. I *believe* that what's happening is that Vala is calling g_static_rec_mutex_init to initialize the lock only after some threads are already waiting in the lock() statement. Then those threads remain deadlocked, I think. (By the way, this problem recently caused a subtle hang in Shotwell, which was using the design pattern above to initialize certain singleton objects.)
Static fields in Vala are initialized in the class initialization function (as they are supposed to be--see http://developer.gnome.org/gobject/stable/gobject-Type-Information.html#GClassInitFunc), and you are indeed trying to use the lock before that occurs (basically when the first instance of Foo is created). In my opinion this test case failing isn't actually a bug, it is the expected behavior. I the same pattern from time to time, and I didn't realize it was broken until now. The problem is that I don't see a good way to do it right now... the only think I can think of would be using external code to initialize a mutex /before/ calling Foo.get_instance, which is moderately horrible. Perhaps fixing #627293 would be the right solution? Then you could just do something like public static Foo get_instance () { once { instance = new Foo (); } return instance; }
Yes, that would be great.
GOnce has been in for a while (Thu Apr 18 12:11:08 2013 +0200), though not with syntax support as above. However, it should be usable, and I don't think there is a solution to this without something like __attribute__((constructor)) (which isn't portable), so I'm going to close this. If the GOnce stuff is insufficient please reopen.