glib r7541 - trunk/gio
- From: danw svn gnome org
- To: svn-commits-list gnome org
- Subject: glib r7541 - trunk/gio
- Date: Thu, 25 Sep 2008 12:04:53 +0000 (UTC)
Author: danw
Date: Thu Sep 25 12:04:52 2008
New Revision: 7541
URL: http://svn.gnome.org/viewvc/glib?rev=7541&view=rev
Log:
Bug 553426 - cancellable clarifications
* gcancellable.c (g_cancellable_class_init): Add a note to the
"cancelled" signal docs warning about thread-safety issues
(g_cancellable_cancel): Note that cancelling an asynchronous
operation takes effect asynchronously, not immediately.
Modified:
trunk/gio/ChangeLog
trunk/gio/gcancellable.c
Modified: trunk/gio/gcancellable.c
==============================================================================
--- trunk/gio/gcancellable.c (original)
+++ trunk/gio/gcancellable.c Thu Sep 25 12:04:52 2008
@@ -93,11 +93,64 @@
* GCancellable::cancelled:
* @cancellable: a #GCancellable.
*
- * Emitted when the operation has been cancelled from another thread.
+ * Emitted when the operation has been cancelled.
*
- * Can be used by implementations of cancellable operations. This will
- * be emitted in the thread that tried to cancel the operation, not the
- * thread the is running the operation.
+ * Can be used by implementations of cancellable operations. If the
+ * operation is cancelled from another thread, the signal will be
+ * emitted in the thread that cancelled the operation, not the
+ * thread that is running the operation.
+ *
+ * Note that disconnecting from this signal (or any signal) in a
+ * multi-threaded program is prone to race conditions, and it is
+ * possible that a signal handler may be invoked even
+ * <emphasis>after</emphasis> a call to
+ * g_signal_handler_disconnect() for that handler has already
+ * returned. Therefore, code such as the following is wrong in a
+ * multi-threaded program:
+ *
+ * |[
+ * my_data = my_data_new (...);
+ * id = g_signal_connect (cancellable, "cancelled",
+ * G_CALLBACK (cancelled_handler), my_data);
+ *
+ * /<!-- -->* cancellable operation here... *<!-- -->/
+ *
+ * g_signal_handler_disconnect (cancellable, id);
+ * my_data_free (my_data); /<!-- -->* WRONG! *<!-- -->/
+ * /<!-- -->* if g_cancellable_cancel() is called from another
+ * * thread, cancelled_handler() may be running at this point,
+ * * so it's not safe to free my_data.
+ * *<!-- -->/
+ * ]|
+ *
+ * The correct way to free data (or otherwise clean up temporary
+ * state) in this situation is to use g_signal_connect_data() (or
+ * g_signal_connect_closure()) to connect to the signal, and do the
+ * cleanup from a #GClosureNotify, which will not be called until
+ * after the signal handler is both removed and not running:
+ *
+ * |[
+ * static void
+ * cancelled_disconnect_notify (gpointer my_data, GClosure *closure)
+ * {
+ * my_data_free (my_data);
+ * }
+ *
+ * ...
+ *
+ * my_data = my_data_new (...);
+ * id = g_signal_connect_data (cancellable, "cancelled",
+ * G_CALLBACK (cancelled_handler), my_data,
+ * cancelled_disconnect_notify, 0);
+ *
+ * /<!-- -->* cancellable operation here... *<!-- -->/
+ *
+ * g_signal_handler_disconnect (cancellable, id);
+ * /<!-- -->* cancelled_disconnect_notify() may or may not have
+ * * already been called at this point, so the code has to treat
+ * * my_data as though it has been freed.
+ * *<!-- -->/
+ * ]|
*/
signals[CANCELLED] =
g_signal_new (I_("cancelled"),
@@ -278,7 +331,7 @@
* @cancellable: a #GCancellable object.
* @error: #GError to append error state to.
*
- * If the @cancelalble is cancelled, sets the error to notify
+ * If the @cancellable is cancelled, sets the error to notify
* that the operation was cancelled.
*
* Returns: %TRUE if @cancellable was cancelled, %FALSE if it was not.
@@ -334,12 +387,20 @@
* g_cancellable_cancel:
* @cancellable: a #GCancellable object.
*
- * Will set @cancellable to cancelled, and will emit the CANCELLED
- * signal.
+ * Will set @cancellable to cancelled, and will emit the
+ * #GCancellable::cancelled signal. (However, see the warning about
+ * race conditions in the documentation for that signal if you are
+ * planning to connect to it.)
*
- * This function is thread-safe. In other words, you can safely call it from
- * another thread than the one running an operation that was passed
- * the @cancellable.
+ * This function is thread-safe. In other words, you can safely call
+ * it from a thread other than the one running the operation that was
+ * passed the @cancellable.
+ *
+ * The convention within gio is that cancelling an asynchronous
+ * operation causes it to complete asynchronously. That is, if you
+ * cancel the operation from the same thread in which it is running,
+ * then the operation's #GAsyncReadyCallback will not be invoked until
+ * the application returns to the main loop.
**/
void
g_cancellable_cancel (GCancellable *cancellable)
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]