Gobject tutorial 九

2024-06-21 21:20
文章标签 tutorial gobject

本文主要是介绍Gobject tutorial 九,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

The GObject messaging system

Closures

closure是一个抽象、通用的概念,它包含一个函数和一些变量。作用就是实现函数回调功能。

我们看看GLib对closure是怎么定义的。

/*** GClosure:* @in_marshal: Indicates whether the closure is currently being invoked with *  g_closure_invoke()* @is_invalid: Indicates whether the closure has been invalidated by *  g_closure_invalidate()* * A #GClosure represents a callback supplied by the programmer.*/
struct _GClosure
{/*< private >*/guint ref_count : 15;  /* (atomic) *//* meta_marshal is not used anymore but must be zero for historical reasonsas it was exposed in the G_CLOSURE_N_NOTIFIERS macro */guint meta_marshal_nouse : 1;  /* (atomic) */guint n_guards : 1;  /* (atomic) */guint n_fnotifiers : 2;  /* finalization notifiers (atomic) */guint n_inotifiers : 8;  /* invalidation notifiers (atomic) */guint in_inotify : 1;  /* (atomic) */guint floating : 1;  /* (atomic) *//*< protected >*/guint derivative_flag : 1;  /* (atomic) *//*< public >*/guint in_marshal : 1;  /* (atomic) */guint is_invalid : 1;  /* (atomic) *//*< private >*/	void   (*marshal)  (GClosure       *closure,GValue /*out*/ *return_value,guint           n_param_values,const GValue   *param_values,gpointer        invocation_hint,gpointer	    marshal_data);/*< protected >*/	gpointer data;/*< private >*/	GClosureNotifyData *notifiers;/* invariants/constraints:* - ->marshal and ->data are _invalid_ as soon as ->is_invalid==TRUE* - invocation of all inotifiers occurs prior to fnotifiers* - order of inotifiers is random*   inotifiers may _not_ free/invalidate parameter values (e.g. ->data)* - order of fnotifiers is random* - each notifier may only be removed before or during its invocation* - reference counting may only happen prior to fnotify invocation*   (in that sense, fnotifiers are really finalization handlers)*/
};

对于不同的runtime,closure有不同具体实现,对于C/C++而言,这个具体的实现就是GCClosure.

其定义如下:

struct _GCClosure
{GClosure	closure;gpointer	callback;
};

 g_cclosure_new、g_cclosure_new_swap都是用于创建closure的函数,创建完成的closure会以用户提供的数据为参数,调用用户提供的callback_func。二者的不同在于,用户提的的数据作为参数传递给函数时,数据在参数中的位置不同,对于g_cclosure_new,用户的参数是作为最后一个参数,而对于g_cclosure_new_swap,用户的数据作为第一个参数的。

我们注意到,在GClosure的定义中,有一个函数指针,marshaller,对于C语言来说,这个函数的作用是将一组GValue转换为c格式的参数列表,这组GValue代表的是即将传递给回调函数的参数。当参数转换完成后,marhaaller还会调用用户提供的回调函数,并以刚刚转换完成的参数列表作为参数。当回调函数执行完成后,有将函数的返回结果转换成GValue类型,并将GValue返回到marshaller的调用者。

Glib中有一个通用的函数,g_cclosure_marshal_generic,我们在平常在调用g_signal_new时,当将其参数c_marshaller设置为NULL时,g_cclosure_marshal_generic就是此时的默认marshaller.当然,还存在其他的marshaller,比如说g_cclosure_marshal_VOID__INT。

我们以g_cclosure_marshal_generic为例,看看marshaller的执行流程

/*** g_cclosure_marshal_generic:* @closure: A #GClosure.* @return_gvalue: A #GValue to store the return value. May be %NULL*   if the callback of closure doesn't return a value.* @n_param_values: The length of the @param_values array.* @param_values: An array of #GValues holding the arguments*   on which to invoke the callback of closure.* @invocation_hint: The invocation hint given as the last argument to*   g_closure_invoke().* @marshal_data: Additional data specified when registering the*   marshaller, see g_closure_set_marshal() and*   g_closure_set_meta_marshal()** A generic marshaller function implemented via* [libffi](http://sourceware.org/libffi/).** Normally this function is not passed explicitly to g_signal_new(),* but used automatically by GLib when specifying a %NULL marshaller.** Since: 2.30*/
void
g_cclosure_marshal_generic (GClosure     *closure,GValue       *return_gvalue,guint         n_param_values,const GValue *param_values,gpointer      invocation_hint,gpointer      marshal_data)
{ffi_type *rtype;void *rvalue;int n_args;ffi_type **atypes;void **args;int i;ffi_cif cif;GCClosure *cc = (GCClosure*) closure;gint *enum_tmpval;gboolean tmpval_used = FALSE;enum_tmpval = g_alloca (sizeof (gint));if (return_gvalue && G_VALUE_TYPE (return_gvalue)){rtype = value_to_ffi_type (return_gvalue, &rvalue, enum_tmpval, &tmpval_used);}else{rtype = &ffi_type_void;}rvalue = g_alloca (MAX (rtype->size, sizeof (ffi_arg)));n_args = n_param_values + 1;atypes = g_alloca (sizeof (ffi_type *) * n_args);args =  g_alloca (sizeof (gpointer) * n_args);if (tmpval_used)enum_tmpval = g_alloca (sizeof (gint));if (G_CCLOSURE_SWAP_DATA (closure)){atypes[n_args-1] = value_to_ffi_type (param_values + 0,&args[n_args-1],enum_tmpval,&tmpval_used);atypes[0] = &ffi_type_pointer;args[0] = &closure->data;}else{atypes[0] = value_to_ffi_type (param_values + 0,&args[0],enum_tmpval,&tmpval_used);atypes[n_args-1] = &ffi_type_pointer;args[n_args-1] = &closure->data;}for (i = 1; i < n_args - 1; i++){if (tmpval_used)enum_tmpval = g_alloca (sizeof (gint));atypes[i] = value_to_ffi_type (param_values + i,&args[i],enum_tmpval,&tmpval_used);}if (ffi_prep_cif (&cif, FFI_DEFAULT_ABI, n_args, rtype, atypes) != FFI_OK)return;ffi_call (&cif, marshal_data ? marshal_data : cc->callback, rvalue, args);if (return_gvalue && G_VALUE_TYPE (return_gvalue))value_from_ffi_type (return_gvalue, rvalue);
}

Signals

在之前的例子中,我们在应用程序中使用过signal, 接下来,我们深入聊聊signal背后的逻辑。

信号的作用是连接特定用户事件与事件监听者。例如,在GTK中, 当窗口系统收到用户事件(比如键盘敲击事件、鼠标移动事件),窗口系统会生成GTK事件,并通过信号的形式发送到widget对象实例。

信号会在注册过程中会与具体的对象类型进行绑定,这意味着此对象类型会发出这个信号。在父对象类型注册的信号在其子对象类型也能使用。信号发生过程中会使用到closure.用户能通过连接到信号的closure控制发出或者停止发出信号。当一个类型实例上有信号发出,这个类型实例上所有连接到此信号的closure都会被调用。

为一个存在的对象类型注册新信号时,会使用函数g_signal_newv()、g_signal_new_valist()以及g_signal_new()。g_signal_new_valist()和g_signal_new()都是通过g_signal_newv()来实现的,我们看看GLib中g_signal_newv()中的声明。

/*** g_signal_newv:* @signal_name: the name for the signal* @itype: the type this signal pertains to. It will also pertain to*     types which are derived from this type* @signal_flags: a combination of #GSignalFlags specifying detail of when*     the default handler is to be invoked. You should at least specify*     %G_SIGNAL_RUN_FIRST or %G_SIGNAL_RUN_LAST* @class_closure: (nullable): The closure to invoke on signal emission;*     may be %NULL* @accumulator: (nullable): the accumulator for this signal; may be %NULL* @accu_data: (nullable) (closure accumulator): user data for the @accumulator* @c_marshaller: (nullable): the function to translate arrays of*     parameter values to signal emissions into C language callback*     invocations or %NULL* @return_type: the type of return value, or %G_TYPE_NONE for a signal*     without a return value* @n_params: the length of @param_types* @param_types: (array length=n_params) (nullable): an array of types, one for*     each parameter (may be %NULL if @n_params is zero)** Creates a new signal. (This is usually done in the class initializer.)** See g_signal_new() for details on allowed signal names.** If c_marshaller is %NULL, g_cclosure_marshal_generic() will be used as* the marshaller for this signal.** Returns: the signal id*/
guint
g_signal_newv (const gchar       *signal_name,GType              itype,GSignalFlags       signal_flags,GClosure          *class_closure,GSignalAccumulator accumulator,gpointer		  accu_data,GSignalCMarshaller c_marshaller,GType		  return_type,guint              n_params,GType		 *param_types)

可以看出,信号基本就是对连接到信号的closure的描述。

信号在发送过程中会调用一系列的回调函数。这些回调函数主要分为两类:per-object类和用户提供的。per-object类回调函数通常称为"object method handler" 或者"default(signal)handler",用户提供的回调函数通常称为“signal handler"。

所有的handler都将对象类型实例指针作为第一个参数,将一个gpointer user_data作为最后一个参数,signal-define 参数在两者之间,user_data中通常会有用户在连接handler到信号时所提供的数据。回调函数的类型是GCallback。

一个正常的信号发送过程包含五个阶段,除非中间的过程被打断。

  1. 为设置了G_SIGNAL_RUN_FIRST flag的信号调用 default handler
  2. 调用用户提供的signal handler(signal handler 不是通过g_signal_connect_after与信号进行连接的)
  3. 为设置了G_SIGNAL_RUN_LAST flag的信号调用default handler
  4. 调用用户提供的signal handler(signal handler 不是通过g_signal_connect_after与信号进行连接的)
  5. 为设置了G_SIGNAL_RUN_CLEANUP flag的信号调用default handler

用户提供的signal handler是以他们连接到信号的先后顺序执行的。

这篇关于Gobject tutorial 九的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1082363

相关文章

A Tutorial on Near-Field XL-MIMO Communications Towards 6G【论文阅读笔记】

此系列是本人阅读论文过程中的简单笔记,比较随意且具有严重的偏向性(偏向自己研究方向和感兴趣的),随缘分享,共同进步~ 论文主要内容: 建立XL-MIMO模型,考虑NUSW信道和非平稳性; 基于近场信道模型,分析性能(SNR scaling laws,波束聚焦、速率、DoF) XL-MIMO设计问题:信道估计、波束码本、波束训练、DAM XL-MIMO信道特性变化: UPW ➡ NU

beanstalkc Tutorial 中文版

英文原版:https://github.com/earl/beanstalkc/blob/wip-doc-rtfd/doc/tutorial.rst 背景介绍: Beanstalk,一个高性能、轻量级的分布式内存队列系统。而beanstalkc是Beanstalk的一个python客户端库。看题主写的通俗易懂,就直接翻译过来。 开始: 启动服务端beanstalkd进程来监听14711端口,可以

OpenGuass under Ubuntu_22.04 install tutorial

今天开始短学期课程:数据库课程设计。今天9点左右在SL1108开课,听陈老师讲授了本次短学期课程的要求以及任务安排,随后讲解了国产数据库的三层架构的逻辑。配置了大半天才弄好,放一张成功的图片,下面开始记录成功的步骤: My operator system is Ubuntu_22.04. procedures sudo wget https://opengauss.obs.cn-so

Tutorial : Getting Started with Kubernetes on your Windows Laptop with Minikube

https://rominirani.com/tutorial-getting-started-with-kubernetes-on-your-windows-laptop-with-minikube-3269b54a226#.d9lmuvzf2 本文的注意事项: 1, 截止到2017.01.20, window上的kubernetes依然是实验性的, 存在各种不可预知的bug

OpenCV2.4.10之samples_cpp_tutorial-code_learn-----ImgTrans(仿射变换)

本系列学习笔记参考自OpenCV2.4.10之opencv\sources\samples\cpp\tutorial_code和http://www.opencv.org.cn/opencvdoc/2.3.2/html/genindex.html 本博文将继续学习opencv-tutorial-code中的ImgTrans,这里讲主要介绍仿射变换。仿射变换是直角坐标系的一种,描述的是一

OpenCV2.4.10之samples_cpp_tutorial-code_learn-----ImgTrans(图片边框与图片卷积)

本系列学习笔记参考自OpenCV2.4.10之 opencv\sources\samples\cpp\tutorial_code和 http://www.opencv.org.cn/opencvdoc/2.3.2/html/genindex.html 本博文将继续介绍如何给一张图片添加边框以及如何对一张图片进行卷积。核心函数为copyMakeBorder与filter2D 1.co

OpenCV2.4.10之samples_cpp_tutorial-code_learn-----ImgTrans(Canny边缘检测)

本系列学习笔记参考自OpenCV2.4.10之 opencv\sources\samples\cpp\tutorial_code和 http://www.opencv.org.cn/opencvdoc/2.3.2/html/genindex.html 本博文接下来将介绍图像变换相关的Demo,如下图所示: CannyDetector_Demo.cpp(Canny边缘检测)

OpenCV2.4.10之samples_cpp_tutorial-code_learn-----ImgProc(图像处理)

本系列学习笔记参考自OpenCV2.4.10之 opencv\sources\samples\cpp\tutorial_code和 http://www.opencv.org.cn/opencvdoc/2.3.2/html/genindex.html       本博文将继续学习 OpenCV2.4.10中tutorial-code下的ImgProc,还有对于涉及到的知

OpenCV2.4.10之samples_cpp_tutorial-code_learn------安装配置与第一个Opencv程序

本系列学习笔记参考自OpenCV2.4.10之 opencv\sources\samples\cpp\tutorial_code和 http://www.opencv.org.cn/opencvdoc/2.3.2/html/genindex.html opencv作为一个开源的二维图形库,提供了一套完整的二维图像处理等相关算法的C/C++实现。自opencv2.0版

【kaldi】Kaldi tutorial翻译之Prerequisites(前提条件)-kaldi学习前必备梳理

本翻译仅供自己学习使用,不承担任何其他责任。水平有限拒绝转载。欢迎大家指出错误,共同学习。 我们假设本页的读者了解使用HMM-GMM进行语音识别的基础知识。在这里我们需要在线简明介绍的是:M. Gales and S. Young (2007).``The Application of Hidden Markov Models in Speech Recognition."