当前位置:网站首页>【无标题】
【无标题】
2022-07-23 13:17:00 【Jorhson_Deng】
<div id="article_content" class="article_content clearfix">
<link rel="stylesheet" href="https://csdnimg.cn/release/blogv2/dist/mdeditor/css/editerView/ck_htmledit_views-bbac9290cd.css">
<div id="content_views" class="markdown_views prism-atom-one-dark">
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
<path stroke-linecap="round" d="M5,0 0,2.5 5,5z" id="raphael-marker-block" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></path>
</svg>
<p>原文:<a href="https://blog.csdn.net/jack0106/article/details/6258422">https://blog.csdn.net/jack0106/article/details/6258422</a><br> 作者联系方式:冯牮 [email protected]<br> <br></p>
<p><strong>Glib 源码</strong>:<a href="https://download.gnome.org/sources/glib/">https://download.gnome.org/sources/glib/</a><br> <strong>GLib API</strong>:<a href="https://developer.gnome.org/glib/stable/">https://developer.gnome.org/glib/stable/</a></p>
<br>
<p></p>
<div class="toc">
<h3><a name="t0"></a> </h3>
<ul><li><a href="#_17" target="_self">引入</a></li><li><a href="#GMainLoop_105" target="_self">GMainLoop的实现机制</a></li><li><ul><li><a href="#GSource_110" target="_self">GSource</a></li><li><a href="#GMainContext_131" target="_self">GMainContext</a></li></ul>
</li></ul>
</div>
<p></p>
<br>
<p>做linux程序开发有一段时间了,也使用过好几个UI库,包括gtk,qt,还有clutter。其中感觉最神秘的,就是所谓的“主事件循环"。在qt中,就是QApplication,gtk中是gtk_main(),clutter中则是clutter_main()。这些事件循环对象,都被封装的很“严密",使用的时候,代码都很简单。而我们在编写应用程序的过程中,通常也只需要重载widget的event处理函数(或者是处理event对应的信号),至于event是怎样产生和传递的,这就是个谜。</p>
<br>
<h1><a name="t1"></a><a id="_17"></a>引入</h1>
<p>最近时间比较充裕,仔细研究了一下事件循环,参考的代码是<code>glib</code>中的<code>GMainLoop</code>。<code>gtk_main()</code>和<code>clutter_main()</code>都是基于<code>GMainLoop</code>的。另外,其实事件循环的概念,也不仅仅使用在UI编程中,在网络编程中,同样大量的使用。可以这样说,<strong>event loop</strong> 是编程模型中,最基本的一个概念。可惜在大学教材中,从来没有看到过这个概念,玩单片机的时候,也用不到这个概念,只有在有操作系统的环境下,才会有<strong>event loop</strong>。</p>
<p><strong>event loop</strong>的代码基础,还要用到一个概念 —— <strong><a href="https://www.baidu.com/s?wd=I/O%E7%9A%84%E5%A4%9A%E8%B7%AF%E5%A4%8D%E7%94%A8&rsv_spt=1&rsv_iqid=0x9b813163006f69c2&issp=1&f=8&rsv_bp=1&rsv_idx=2&ie=utf-8&tn=baiduhome_pg&rsv_enter=1&rsv_dl=ib&rsv_sug3=3&rsv_n=2">I/O的多路复用</a></strong>。目前常用的api接口,有3个,<code>select</code>,<code>poll</code>以及<code>epoll</code>。glib是一个跨平台的库,在linux上,使用的是<code>poll</code>函数,在window上,使用的是<code>select</code>。而<code>epoll</code>这个接口,在linux2.6中才正式推出,它的效率比前两者更高,在网络编程中大量使用。而本质上,这三个函数,其实是相同的。</p>
<p>如果对<strong>I/O多路复用</strong>还不了解,请先自行google学习。下面,仅仅给出一个使用poll接口的代码模型片段。</p>
<pre data-index="0" class="prettyprint"><code class="prism language-c has-numbering" οnclick="mdcp.copyCode(event)" style="position: unset;"><span class="token macro property">#<span class="token directive keyword">include</span> <span class="token string"><poll.h></span></span>
<span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
<span class="token keyword">struct</span> pollfd fds<span class="token punctuation">[</span><span class="token number">2</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> timeout_msecs <span class="token operator">=</span> <span class="token number">500</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> ret<span class="token punctuation">;</span>
<span class="token keyword">int</span> i<span class="token punctuation">;</span>
<span class="token comment">/* Open STREAMS device. */</span>
fds<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span>fd <span class="token operator">=</span> <span class="token function">open</span><span class="token punctuation">(</span><span class="token string">"/dev/dev0"</span><span class="token punctuation">,</span> <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
fds<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">.</span>fd <span class="token operator">=</span> <span class="token function">open</span><span class="token punctuation">(</span><span class="token string">"/dev/dev1"</span><span class="token punctuation">,</span> <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
fds<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span>events <span class="token operator">=</span> POLLOUT <span class="token operator">|</span> POLLWRBAND<span class="token punctuation">;</span>
fds<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">.</span>events <span class="token operator">=</span> POLLOUT <span class="token operator">|</span> POLLWRBAND<span class="token punctuation">;</span>
<span class="token keyword">while</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
ret <span class="token operator">=</span> <span class="token function">poll</span><span class="token punctuation">(</span>fds<span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> timeout_msecs<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>ret <span class="token operator">></span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
<span class="token comment">/* An event on one of the fds has occurred. */</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span>i<span class="token operator">=</span><span class="token number">0</span><span class="token punctuation">;</span> i<span class="token operator"><</span><span class="token number">2</span><span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>fds<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">.</span>revents <span class="token operator">&</span> POLLWRBAND<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
<span class="token comment">/* Priority data may be written on device number i. */</span>
<span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
<span class="token punctuation">}</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>fds<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">.</span>revents <span class="token operator">&</span> POLLOUT<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
<span class="token comment">/* Data may be written on device number i. */</span>
<span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
<span class="token punctuation">}</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>fds<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">.</span>revents <span class="token operator">&</span> POLLHUP<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
<span class="token comment">/* A hangup has occurred on device number i. */</span>
<span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
<div class="hljs-button {2}" data-title="复制"></div></code><ul class="pre-numbering" style=""><li style="color: rgb(153, 153, 153);">1</li><li style="color: rgb(153, 153, 153);">2</li><li style="color: rgb(153, 153, 153);">3</li><li style="color: rgb(153, 153, 153);">4</li><li style="color: rgb(153, 153, 153);">5</li><li style="color: rgb(153, 153, 153);">6</li><li style="color: rgb(153, 153, 153);">7</li><li style="color: rgb(153, 153, 153);">8</li><li style="color: rgb(153, 153, 153);">9</li><li style="color: rgb(153, 153, 153);">10</li><li style="color: rgb(153, 153, 153);">11</li><li style="color: rgb(153, 153, 153);">12</li><li style="color: rgb(153, 153, 153);">13</li><li style="color: rgb(153, 153, 153);">14</li><li style="color: rgb(153, 153, 153);">15</li><li style="color: rgb(153, 153, 153);">16</li><li style="color: rgb(153, 153, 153);">17</li><li style="color: rgb(153, 153, 153);">18</li><li style="color: rgb(153, 153, 153);">19</li><li style="color: rgb(153, 153, 153);">20</li><li style="color: rgb(153, 153, 153);">21</li><li style="color: rgb(153, 153, 153);">22</li><li style="color: rgb(153, 153, 153);">23</li><li style="color: rgb(153, 153, 153);">24</li><li style="color: rgb(153, 153, 153);">25</li><li style="color: rgb(153, 153, 153);">26</li><li style="color: rgb(153, 153, 153);">27</li><li style="color: rgb(153, 153, 153);">28</li><li style="color: rgb(153, 153, 153);">29</li><li style="color: rgb(153, 153, 153);">30</li><li style="color: rgb(153, 153, 153);">31</li><li style="color: rgb(153, 153, 153);">32</li><li style="color: rgb(153, 153, 153);">33</li><li style="color: rgb(153, 153, 153);">34</li></ul></pre>
<p>上面这个代码,我们可以把它拆分成3部分:</p>
<ol><li>准备要检测的文件集合(不是简单的准备“文件描述符"的集合,而是准备<code>struct pollfd</code>结构体的集合。这就包括了文件描述符,以及希望监控的事件,如可读/可写/或可执行其他操作等)。</li></ol>
<pre data-index="1" class="prettyprint"><code class="prism language-c has-numbering" οnclick="mdcp.copyCode(event)" style="position: unset;"><span class="token keyword">struct</span> pollfd <span class="token punctuation">{<!-- --></span>
<span class="token keyword">int</span> fd<span class="token punctuation">;</span> <span class="token comment">/* 文件描述符 */</span>
<span class="token keyword">short</span> events<span class="token punctuation">;</span> <span class="token comment">/* 等待的事件 */</span>
<span class="token keyword">short</span> revents<span class="token punctuation">;</span> <span class="token comment">/* 实际发生了的事件 */</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
<div class="hljs-button {2}" data-title="复制"></div></code><ul class="pre-numbering" style=""><li style="color: rgb(153, 153, 153);">1</li><li style="color: rgb(153, 153, 153);">2</li><li style="color: rgb(153, 153, 153);">3</li><li style="color: rgb(153, 153, 153);">4</li><li style="color: rgb(153, 153, 153);">5</li></ul></pre>
<ol start="2"><li> <p>执行<code>poll</code>,等待事件发生(文件描述符对应的文件可读/可写/或可执行其他操作等)或者是函数超时返回。</p> </li><li> <p>遍历文件集合(<code>struct pollfd</code>结构体的集合),判断具体是哪些文件有“事件"发生,并且进一步判断是何种“事件"。然后,根据需求,执行对应的操作(上面的代码中,用…表示的对应操作)。</p> </li></ol>
<p>其中<strong>2</strong>和<strong>3</strong>对应的代码,都放在一个<code>while</code>循环中。而在<strong>3</strong>中所谓的“对应的操作",还可以包括一种“退出"操作,这样的话,就可以从<code>while</code>循环中退出,这样的话,整个进程也有机会正常结束。<br> <br><br> <strong>再次提醒一下,请先把上面这段代码看懂,最好是有过实际的使用经验,这样更有助于理解。</strong><br> <br><br> 下面开始讨论重点。这段代码仅仅是演示,所以它很简单。但是,从另外一个角度来看,这个代码片段又很死板,尤其是对于新手或者是没有I/O多路复用实际使用经验的朋友来说,很容易被这段代码模型“框住"。它还能变得更灵活吗?怎样才能变得更灵活?详细解释之前,先提几个小问题。</p>
<ol><li> <p>前面的代码,仅打开了2个文件,并且传递给poll函数。如果,在程序运行过程中,想动态的增加或者删除<code>poll</code>函数监控的文件,怎么办?</p> </li><li> <p>前面的代码,设置的超时时间,是固定的。假设,某个时刻有100个文件需要被监控,而针对这100个不同的文件,每个文件期望设置的超时时间都不一样,怎么办?</p> </li><li> <p>前面的代码,当<code>poll</code>函数返回,对文件集合进行遍历的时候,是逐个进行判断并且执行“对应的操作"。如果,有100个文件被监控,当<code>poll</code>返回时,这100个文件,都满足条件,可以进行“对应的操作",其中的50个文件的“对应的操作"很耗时间,但是并不是这么紧急(可以稍后再处理,比如等到下一轮<code>poll</code>返回时再处理),而另外50个文件的“对应的操作”需要立即执行,并且很快(在下一次<code>poll</code>的时候)又会有新的事件发生并且满足判断时的条件,怎么办?</p> </li></ol>
<p>对第1个问题,可以想到,需要对 <strong>所有的文件</strong>(<code>struct pollfd</code>)做一个统一的管理,需要有添加和删除文件的功能。用面向对象的思想来看,这就是一个类,暂且叫做<strong>类A</strong>。</p>
<p>对第2个问题,可以想到,还需要对 <strong>每一个被监控的文件</strong>(<code>struct pollfd</code>)做更多的控制。也可以用一个类来包装被监控的文件,对这个文件进行管理,在该对象中,包含了<code>struct pollfd</code>结构体,该类还可以提供对应的文件所期望的超时时间。暂且叫做<strong>类B</strong>。</p>
<p>对第3个问题,可以考虑为每一个被监控的文件设置一个优先级,然后就可以根据优先级优先执行更“紧急"的“对应的操作"。这个优先级信息,也可以存储在<strong>类B</strong>中。设计出了<strong>类B</strong>之后,<strong>类A</strong>就不再是直接统一管理文件了,而是变成统一管理<strong>类B</strong>,可以看成是<strong>类B</strong>的一个容器类。</p>
<p>有了这3个解答之后,就可以对这个代码片段添油加醋,重新组装,让它变得更灵活了。<code>glib</code>中的<code>GMainLoop</code>,做的就是这样的事情,而且,它做的事情,除了这3个解答中描述的内容外,还有更让人“吃惊的惊喜"。</p>
<p>,这里又要提醒一下了,下面将对<code>GMainLoop</code>进行描述,所以,最好是先使用一下<code>GMainLoop</code>,包括其中的<code>g_timeout_source_new(guint interval)</code>,<code>g_idle_source_new(void)</code>以及<code>g_child_watch_source_new(GPid pid)</code>。顺便再强调一下,学习编程的最好的办法,就是看代码,而且是看高质量的代码。</p>
<br>
<h1><a name="t2"></a><a id="GMainLoop_105"></a>GMainLoop的实现机制</h1>
<p>后面的讲解,主要是从原理上来介绍<code>GMainLoop</code>的实现机制,并不是代码的情景分析。代码( <strong>gmain.c</strong>)的详细阅读,还是需要自己老老实实的去实践的。后面的这些介绍,只是为了帮助大家更容易的理解源代码。</p>
<p><code>glib</code>的主事件循环框架,由3个类来实现,<code>GMainLoop</code>,<code>GMainContext</code>和<code>GSource</code>,其中的<code>GMainLoop</code>仅仅是<code>GMainContext</code>的一个外壳,最重要的,还是<code>GMainContext</code>和<code>GSource</code>。<code>GMainContext</code>就相当于前面提到的<strong>类A</strong>,而<code>GSource</code>就相当于前面提到的<strong>类B</strong>。从原理上讲,<font color="red" size="4"><strong><code>g_main_loop_run(GMainLoop *loop)</code>这个函数的内部实现,和前面代码片段中的<code>while</code>循环,是一致的</strong>。</font>(还有一点要说明的,在<a href="https://so.csdn.net/so/search?q=%E5%A4%9A%E7%BA%BF%E7%A8%8B&spm=1001.2101.3001.7020" target="_blank" class="hl hl-1" data-report-click="{"spm":"1001.2101.3001.7020","dest":"https://so.csdn.net/so/search?q=%E5%A4%9A%E7%BA%BF%E7%A8%8B&spm=1001.2101.3001.7020"}" data-tit="多线程" data-pretit="多线程">多线程</a>的环境下,<code>GMainLoop</code>的代码实现显得比较复杂,为了学习起来更容易些,可以先不考虑<code>GMainLoop</code>中线程相关的代码,这样的话,整体结构就和前面的代码片段是一致的。后面的讲解以及代码片段,都略去了线程相关的代码,这并不影响对event loop的学习和理解)。</p>
<h2><a name="t3"></a><a id="GSource_110"></a>GSource</h2>
<p><code>GSource</code>相当于前面提到的<strong>类B</strong>,它里面会保存优先级信息。同时,<code>GSource</code>要管理对应的文件(保存<code>struct pollfd</code>结构体的指针,而且是<em>以链表的形式保存</em>),而且,<code>GSource</code>和被管理的文件的对应关系,不是 1对1,而是 1对n。这个n,甚至可以是0(这就是一个“吃惊的惊喜",后面会有更详细的解释)。<code>GSource</code>还必须提供3个重要的函数(从面向对象的角度看,<code>GSource</code>是一个抽象类,而且有三个重要的纯虚函数,需要子类来具体实现),这3个函数就是:</p>
<pre data-index="2" class="prettyprint"><code class="prism language-c has-numbering" οnclick="mdcp.copyCode(event)" style="position: unset;"> gboolean <span class="token punctuation">(</span><span class="token operator">*</span>prepare<span class="token punctuation">)</span><span class="token punctuation">(</span>GSource <span class="token operator">*</span>source<span class="token punctuation">,</span> gint <span class="token operator">*</span>timeout_<span class="token punctuation">)</span><span class="token punctuation">;</span>
gboolean <span class="token punctuation">(</span><span class="token operator">*</span>check<span class="token punctuation">)</span><span class="token punctuation">(</span>GSource <span class="token operator">*</span>source<span class="token punctuation">)</span><span class="token punctuation">;</span>
gboolean <span class="token punctuation">(</span><span class="token operator">*</span>dispatch<span class="token punctuation">)</span><span class="token punctuation">(</span>GSource <span class="token operator">*</span>source<span class="token punctuation">,</span> GSourceFunc callback<span class="token punctuation">,</span> gpointer user_data<span class="token punctuation">)</span><span class="token punctuation">;</span>
<div class="hljs-button {2}" data-title="复制"></div></code><ul class="pre-numbering" style=""><li style="color: rgb(153, 153, 153);">1</li><li style="color: rgb(153, 153, 153);">2</li><li style="color: rgb(153, 153, 153);">3</li><li style="color: rgb(153, 153, 153);">4</li><li style="color: rgb(153, 153, 153);">5</li></ul></pre>
<p>再看一下前面代码片段中的3部分,这个<code>prepare</code>函数,就是要在第一部分被调用的,<code>check</code>和<code>dispathch</code>函数,就是在第3部分被调用的。有一点区别是,<code>prepare</code>函数也要放到<code>while</code>循环中,而不是在循环之外(因为要动态的增加或者删除<code>poll</code>函数监控的文件)。</p>
<p><code>prepare</code>函数,会在执行<code>poll</code>之前被调用。该<code>GSource</code>中的<code>struct pollfd</code>是否希望被<code>poll</code>函数监控,就由<code>prepare</code>函数的返回值来决定。同时,该<code>GSource</code>希望的超时时间,也由参数<code>timeout_</code>返回。</p>
<p><code>check</code>函数,在执行<code>poll</code>之后被调用。该<code>GSource</code>中的<code>struct pollfd</code>是否有事件发生,就由<code>check</code>函数的返回值来描述(在<code>check</code>函数中可以检测<code>struct pollfd</code>结构体中的返回信息)。</p>
<p><code>dispatch</code>函数,在执行<code>poll</code>和<code>check</code>函数之后被调用,并且,仅当对应的<code>check</code>函数返回true的时候,对应的<code>dispatch</code>函数才会被调用,<code>dispatch</code>函数,就相当于“对应的操作"。<br> <img src="https://img-blog.csdnimg.cn/20200311164535617.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTM1NTQyMTM=,size_16,color_FFFFFF,t_70" alt="状态转化关系图"></p>
<h2><a name="t4"></a><a id="GMainContext_131"></a>GMainContext</h2>
<p><code>GMainContext</code>是<code>GSource</code>的容器,<code>GSource</code>可以添加到<code>GMainContext</code>里面(间接的就把<code>GSource</code>中的<code>struct pollfd</code>也添加到<code>GMainContext</code>里面了),<code>GSource</code>也可以从<code>GMainContext</code>中移除(间接的就把<code>GSource</code>中的<code>struct pollfd</code>从<code>GMainContext</code>中移除了)。<code>GMainContext</code>可以遍历<code>GSource</code>,自然就有机会调用每个<code>GSource</code>的<code>prepare/check/dispatch</code>函数,可以根据每个<code>GSource</code>的<code>prepare</code>函数的返回值来决定,是否要在<code>poll</code>函数中,监控该<code>GSource</code>管理的文件。当然可以根据<code>GSource</code>的优先级进行排序。当<code>poll</code>返回后,可以根据每个<code>GSource</code>的<code>check</code>函数的返回值来决定是否需要调用对应的<code>dispatch</code>函数。</p>
<p>下面给出关键的代码片段,其中的<code>g_main_context_iterate()</code>函数,就相当于前面代码片段中的循环体中要做的动作。循环的退出,则是靠<code>loop->is_running</code>这个标记变量来标识的。</p>
<pre data-index="3" class="prettyprint"><code class="prism language-c has-numbering" οnclick="mdcp.copyCode(event)" style="position: unset;"><span class="token keyword">void</span> g_main_loop_run <span class="token punctuation">(</span>GMainLoop <span class="token operator">*</span>loop<span class="token punctuation">)</span>
<span class="token punctuation">{<!-- --></span>
GThread <span class="token operator">*</span>self <span class="token operator">=</span> G_THREAD_SELF<span class="token punctuation">;</span>
g_return_if_fail <span class="token punctuation">(</span>loop <span class="token operator">!=</span> <span class="token constant">NULL</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
g_return_if_fail <span class="token punctuation">(</span>g_atomic_int_get <span class="token punctuation">(</span><span class="token operator">&</span>loop<span class="token operator">-></span>ref_count<span class="token punctuation">)</span> <span class="token operator">></span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>g_main_context_acquire <span class="token punctuation">(</span>loop<span class="token operator">-></span>context<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">{<!-- --></span>
<span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
<span class="token punctuation">}</span> <span class="token keyword">else</span>
LOCK_CONTEXT <span class="token punctuation">(</span>loop<span class="token operator">-></span>context<span class="token punctuation">)</span><span class="token punctuation">;</span>
g_atomic_int_inc <span class="token punctuation">(</span><span class="token operator">&</span>loop<span class="token operator">-></span>ref_count<span class="token punctuation">)</span><span class="token punctuation">;</span>
loop<span class="token operator">-></span>is_running <span class="token operator">=</span> TRUE<span class="token punctuation">;</span>
<span class="token keyword">while</span> <span class="token punctuation">(</span>loop<span class="token operator">-></span>is_running<span class="token punctuation">)</span>
g_main_context_iterate <span class="token punctuation">(</span>loop<span class="token operator">-></span>context<span class="token punctuation">,</span> TRUE<span class="token punctuation">,</span> TRUE<span class="token punctuation">,</span> self<span class="token punctuation">)</span><span class="token punctuation">;</span>
UNLOCK_CONTEXT <span class="token punctuation">(</span>loop<span class="token operator">-></span>context<span class="token punctuation">)</span><span class="token punctuation">;</span>
g_main_context_release <span class="token punctuation">(</span>loop<span class="token operator">-></span>context<span class="token punctuation">)</span><span class="token punctuation">;</span>
g_main_loop_unref <span class="token punctuation">(</span>loop<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">static</span> gboolean g_main_context_iterate <span class="token punctuation">(</span>GMainContext <span class="token operator">*</span>context<span class="token punctuation">,</span>
gboolean block<span class="token punctuation">,</span> gboolean dispatch<span class="token punctuation">,</span> GThread <span class="token operator">*</span>self<span class="token punctuation">)</span>
<span class="token punctuation">{<!-- --></span>
gint max_priority<span class="token punctuation">;</span>
gint timeout<span class="token punctuation">;</span>
gboolean some_ready<span class="token punctuation">;</span>
gint nfds<span class="token punctuation">,</span> allocated_nfds<span class="token punctuation">;</span>
GPollFD <span class="token operator">*</span>fds <span class="token operator">=</span> <span class="token constant">NULL</span><span class="token punctuation">;</span>
UNLOCK_CONTEXT <span class="token punctuation">(</span>context<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>context<span class="token operator">-></span>cached_poll_array<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
context<span class="token operator">-></span>cached_poll_array_size <span class="token operator">=</span> context<span class="token operator">-></span>n_poll_records<span class="token punctuation">;</span>
context<span class="token operator">-></span>cached_poll_array <span class="token operator">=</span> g_new <span class="token punctuation">(</span>GPollFD<span class="token punctuation">,</span> context<span class="token operator">-></span>n_poll_records<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
allocated_nfds <span class="token operator">=</span> context<span class="token operator">-></span>cached_poll_array_size<span class="token punctuation">;</span>
fds <span class="token operator">=</span> context<span class="token operator">-></span>cached_poll_array<span class="token punctuation">;</span>
UNLOCK_CONTEXT <span class="token punctuation">(</span>context<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">g_main_context_prepare</span><span class="token punctuation">(</span>context<span class="token punctuation">,</span> <span class="token operator">&</span>max_priority<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">while</span> <span class="token punctuation">(</span><span class="token punctuation">(</span>nfds <span class="token operator">=</span> <span class="token function">g_main_context_query</span><span class="token punctuation">(</span>context<span class="token punctuation">,</span> max_priority<span class="token punctuation">,</span> <span class="token operator">&</span>timeout<span class="token punctuation">,</span> fds<span class="token punctuation">,</span>
allocated_nfds<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator">></span> allocated_nfds<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
LOCK_CONTEXT <span class="token punctuation">(</span>context<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">g_free</span><span class="token punctuation">(</span>fds<span class="token punctuation">)</span><span class="token punctuation">;</span>
context<span class="token operator">-></span>cached_poll_array_size <span class="token operator">=</span> allocated_nfds <span class="token operator">=</span> nfds<span class="token punctuation">;</span>
context<span class="token operator">-></span>cached_poll_array <span class="token operator">=</span> fds <span class="token operator">=</span> g_new <span class="token punctuation">(</span>GPollFD<span class="token punctuation">,</span> nfds<span class="token punctuation">)</span><span class="token punctuation">;</span>
UNLOCK_CONTEXT <span class="token punctuation">(</span>context<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>block<span class="token punctuation">)</span>
timeout <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token function">g_main_context_poll</span><span class="token punctuation">(</span>context<span class="token punctuation">,</span> timeout<span class="token punctuation">,</span> max_priority<span class="token punctuation">,</span> fds<span class="token punctuation">,</span> nfds<span class="token punctuation">)</span><span class="token punctuation">;</span>
some_ready <span class="token operator">=</span> <span class="token function">g_main_context_check</span><span class="token punctuation">(</span>context<span class="token punctuation">,</span> max_priority<span class="token punctuation">,</span> fds<span class="token punctuation">,</span> nfds<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>dispatch<span class="token punctuation">)</span>
<span class="token function">g_main_context_dispatch</span><span class="token punctuation">(</span>context<span class="token punctuation">)</span><span class="token punctuation">;</span>
LOCK_CONTEXT <span class="token punctuation">(</span>context<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> some_ready<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<div class="hljs-button {2}" data-title="复制"></div></code><ul class="pre-numbering" style=""><li style="color: rgb(153, 153, 153);">1</li><li style="color: rgb(153, 153, 153);">2</li><li style="color: rgb(153, 153, 153);">3</li><li style="color: rgb(153, 153, 153);">4</li><li style="color: rgb(153, 153, 153);">5</li><li style="color: rgb(153, 153, 153);">6</li><li style="color: rgb(153, 153, 153);">7</li><li style="color: rgb(153, 153, 153);">8</li><li style="color: rgb(153, 153, 153);">9</li><li style="color: rgb(153, 153, 153);">10</li><li style="color: rgb(153, 153, 153);">11</li><li style="color: rgb(153, 153, 153);">12</li><li style="color: rgb(153, 153, 153);">13</li><li style="color: rgb(153, 153, 153);">14</li><li style="color: rgb(153, 153, 153);">15</li><li style="color: rgb(153, 153, 153);">16</li><li style="color: rgb(153, 153, 153);">17</li><li style="color: rgb(153, 153, 153);">18</li><li style="color: rgb(153, 153, 153);">19</li><li style="color: rgb(153, 153, 153);">20</li><li style="color: rgb(153, 153, 153);">21</li><li style="color: rgb(153, 153, 153);">22</li><li style="color: rgb(153, 153, 153);">23</li><li style="color: rgb(153, 153, 153);">24</li><li style="color: rgb(153, 153, 153);">25</li><li style="color: rgb(153, 153, 153);">26</li><li style="color: rgb(153, 153, 153);">27</li><li style="color: rgb(153, 153, 153);">28</li><li style="color: rgb(153, 153, 153);">29</li><li style="color: rgb(153, 153, 153);">30</li><li style="color: rgb(153, 153, 153);">31</li><li style="color: rgb(153, 153, 153);">32</li><li style="color: rgb(153, 153, 153);">33</li><li style="color: rgb(153, 153, 153);">34</li><li style="color: rgb(153, 153, 153);">35</li><li style="color: rgb(153, 153, 153);">36</li><li style="color: rgb(153, 153, 153);">37</li><li style="color: rgb(153, 153, 153);">38</li><li style="color: rgb(153, 153, 153);">39</li><li style="color: rgb(153, 153, 153);">40</li><li style="color: rgb(153, 153, 153);">41</li><li style="color: rgb(153, 153, 153);">42</li><li style="color: rgb(153, 153, 153);">43</li><li style="color: rgb(153, 153, 153);">44</li><li style="color: rgb(153, 153, 153);">45</li><li style="color: rgb(153, 153, 153);">46</li><li style="color: rgb(153, 153, 153);">47</li><li style="color: rgb(153, 153, 153);">48</li><li style="color: rgb(153, 153, 153);">49</li><li style="color: rgb(153, 153, 153);">50</li><li style="color: rgb(153, 153, 153);">51</li><li style="color: rgb(153, 153, 153);">52</li><li style="color: rgb(153, 153, 153);">53</li><li style="color: rgb(153, 153, 153);">54</li><li style="color: rgb(153, 153, 153);">55</li><li style="color: rgb(153, 153, 153);">56</li><li style="color: rgb(153, 153, 153);">57</li><li style="color: rgb(153, 153, 153);">58</li><li style="color: rgb(153, 153, 153);">59</li><li style="color: rgb(153, 153, 153);">60</li></ul></pre>
<p>仔细看一下<code>g_main_context_iterate()</code>函数,也可以把它划分成3个部分,和前面代码片段的3部分对应上。</p>
<ol><li>第一部份,准备要检测的文件集合</li></ol>
<pre data-index="4" class="prettyprint"><code class="prism language-c has-numbering" οnclick="mdcp.copyCode(event)" style="position: unset;"><span class="token function">g_main_context_prepare</span><span class="token punctuation">(</span>context<span class="token punctuation">,</span> <span class="token operator">&</span>max_priority<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">while</span> <span class="token punctuation">(</span><span class="token punctuation">(</span>nfds <span class="token operator">=</span> <span class="token function">g_main_context_query</span><span class="token punctuation">(</span>context<span class="token punctuation">,</span> max_priority<span class="token punctuation">,</span> <span class="token operator">&</span>timeout<span class="token punctuation">,</span> fds<span class="token punctuation">,</span>
allocated_nfds<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator">></span> allocated_nfds<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
LOCK_CONTEXT <span class="token punctuation">(</span>context<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">g_free</span><span class="token punctuation">(</span>fds<span class="token punctuation">)</span><span class="token punctuation">;</span>
context<span class="token operator">-></span>cached_poll_array_size <span class="token operator">=</span> allocated_nfds <span class="token operator">=</span> nfds<span class="token punctuation">;</span>
context<span class="token operator">-></span>cached_poll_array <span class="token operator">=</span> fds <span class="token operator">=</span> g_new <span class="token punctuation">(</span>GPollFD<span class="token punctuation">,</span> nfds<span class="token punctuation">)</span><span class="token punctuation">;</span>
UNLOCK_CONTEXT <span class="token punctuation">(</span>context<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<div class="hljs-button {2}" data-title="复制"></div></code><ul class="pre-numbering" style=""><li style="color: rgb(153, 153, 153);">1</li><li style="color: rgb(153, 153, 153);">2</li><li style="color: rgb(153, 153, 153);">3</li><li style="color: rgb(153, 153, 153);">4</li><li style="color: rgb(153, 153, 153);">5</li><li style="color: rgb(153, 153, 153);">6</li><li style="color: rgb(153, 153, 153);">7</li><li style="color: rgb(153, 153, 153);">8</li><li style="color: rgb(153, 153, 153);">9</li><li style="color: rgb(153, 153, 153);">10</li></ul></pre>
<p>首先是调用<code>g_main_context_prepare(context, &max_priority)</code>,这个就是遍历每个<code>GSource</code>,调用每个<code>GSource</code>的<code>prepare</code>函数,选出一个最高的优先级<code>max_priority</code>,函数内部其实还计算出了一个最短的超时时间。</p>
<p>然后调用<code>g_main_context_query</code>,其实这是再次遍历每个<code>GSource</code>,把优先级等于<code>max_priority</code>的<code>GSource</code>中的<code>struct pollfd</code>,添加到<code>poll</code>的监控集合中。</p>
<p>这个优先级,也是一个“吃惊的惊喜"。按照通常的想法,文件需要被监控的时候,会立刻把它放到监控集合中,但是有了优先级这个概念后,我们就可以有一个“隐藏的后台任务", <code>g_idle_source_new(void)</code>就是最典型的例子。</p>
<ol start="2"><li>第二部份,执行<code>poll</code>,等待事件发生。</li></ol>
<pre data-index="5" class="prettyprint"><code class="prism language-c has-numbering" οnclick="mdcp.copyCode(event)" style="position: unset;"><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>block<span class="token punctuation">)</span>
timeout <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token function">g_main_context_poll</span><span class="token punctuation">(</span>context<span class="token punctuation">,</span> timeout<span class="token punctuation">,</span> max_priority<span class="token punctuation">,</span> fds<span class="token punctuation">,</span> nfds<span class="token punctuation">)</span><span class="token punctuation">;</span>
<div class="hljs-button {2}" data-title="复制"></div></code><ul class="pre-numbering" style=""><li style="color: rgb(153, 153, 153);">1</li><li style="color: rgb(153, 153, 153);">2</li><li style="color: rgb(153, 153, 153);">3</li></ul></pre>
<p>就是调用<code>g_main_context_poll(context, timeout, max_priority, fds, nfds)</code>,<code>g_main_context_poll</code>只是对<code>poll</code>函数的一个简单封装。</p>
<ol start="3"><li>第三部分,遍历文件集合(<code>struct pollfd</code>结构体的集合),执行对应的操作。</li></ol>
<pre data-index="6" class="prettyprint"><code class="prism language-c has-numbering" οnclick="mdcp.copyCode(event)" style="position: unset;">some_ready <span class="token operator">=</span> <span class="token function">g_main_context_check</span><span class="token punctuation">(</span>context<span class="token punctuation">,</span> max_priority<span class="token punctuation">,</span> fds<span class="token punctuation">,</span> nfds<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>dispatch<span class="token punctuation">)</span>
<span class="token function">g_main_context_dispatch</span><span class="token punctuation">(</span>context<span class="token punctuation">)</span><span class="token punctuation">;</span>
<div class="hljs-button {2}" data-title="复制"></div></code><ul class="pre-numbering" style=""><li style="color: rgb(153, 153, 153);">1</li><li style="color: rgb(153, 153, 153);">2</li><li style="color: rgb(153, 153, 153);">3</li></ul></pre>
<p>通常的想法,可能会是这种伪代码形式(这种形式也和前面代码片段的形式是一致的)</p>
<pre data-index="7" class="prettyprint"><code class="prism language-c has-numbering" οnclick="mdcp.copyCode(event)" style="position: unset;"><span class="token function">foreach</span><span class="token punctuation">(</span>all_gsouce<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>gsourc<span class="token operator">-></span>check<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
gsource<span class="token operator">-></span><span class="token function">dispatch</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<div class="hljs-button {2}" data-title="复制"></div></code><ul class="pre-numbering" style=""><li style="color: rgb(153, 153, 153);">1</li><li style="color: rgb(153, 153, 153);">2</li><li style="color: rgb(153, 153, 153);">3</li><li style="color: rgb(153, 153, 153);">4</li><li style="color: rgb(153, 153, 153);">5</li></ul></pre>
<p>实际上,<code>glib</code>的处理方式是,先遍历所有的<code>GSource</code>,执行<code>g_main_context_prepare(context, &max_priority)</code>,调用每个GSource的<code>check</code>函数,然后把满足条件的<code>GSource</code>(<code>check</code>函数返回<code>true</code>的<code>GSource</code>),添加到一个内部链表中。</p>
<p>然后执行<code>g_main_context_dispatch(context)</code>,遍历刚才准备好的内部链表中的<code>GSource</code>,调用每个<code>GSource</code>的<code>dispatch</code>函数。</p>
<br>
<p>ok,分析到此结束,总结一下,重点,首先是要先理解<code>poll</code>函数的使用方法,建立<strong>I/O多路复用</strong>的概念,然后,建议看一下<code>GMainContext</code>的源代码实现,这样才有助于理解。</p>
</div><div><div></div></div>
<link href="https://csdnimg.cn/release/blogv2/dist/mdeditor/css/editerView/markdown_views-3fd7f7a902.css" rel="stylesheet">
<link href="https://csdnimg.cn/release/blogv2/dist/mdeditor/css/style-49037e4d27.css" rel="stylesheet">
</div>
边栏推荐
- COPU副主席刘澎:中国开源在局部领域已接近或达到世界先进水平
- Distance IOU loss: faster and better learning for bounding box regression
- [note] linear regression
- C#入门系列(二十八) -- LINQ的查询语法
- 【笔记】线性回归
- CNCF基金会总经理Priyanka Sharma:一文读懂CNCF运作机制
- pip报错Could not find a version that satisfies the...No matching distribution
- [taro] applet picker dynamically obtains data
- It's not safe to open an account at qiniu business school
- 系统内存介绍和内存管理
猜你喜欢

Direct exchange

主成分分析(MATLAB)

7月HCIP Datacom认证考试通过

UiPath Studio Enterprise 22.4 Crack

Bag of Tricks for Image Classification with Convolutional Neural Networks(卷积神经网络在图像分类中的技巧)

单片机内部IO口保护电路及IO口电气特性以及为什么不同电压IO之间为什么串联一个电阻?

Deep learning convolutional neural network paper study alexnet

YOLOv4: Optimal Speed and Accuracy of Object Detection

国内生产总值(GDP)数据可视化

LeetCode之等式方程的可满足性
随机推荐
Frequently asked questions about MySQL
泰山OFFICE技术讲座:段落边框的布局绘制分析
The working principle of PLL. For example, how can our 8MHz crystal oscillator make MCU work at 48mhz or 72mhz
ts封装localstorage类,存储信息
(resolved) idea compilation gradle project prompt error no symbol found
Practice code - day one
[C language] structure, enumeration and union
分类模型——逻辑回归、Fisher线性判别(SPSS)
Visualization of gross domestic product (GDP) data
一道反序列化的CTF题分享
tensorflow2.X实战系列softmax函数
Deep learning convolutional neural network paper study alexnet
网络协议与攻击模拟:wireshark使用、ARP协议
Chen Wei, head of CPU technology ecology of Alibaba pingtouge: the development road of pingtouge
熵权法优化TOPSIS(MATLAB)
Basic auth plug-in based on apisik authorizes Minio file upload function
国内生产总值(GDP)数据可视化
【Redis】redis安装与客户端redis-cli的使用(批量操作)
无心剑英汉双语诗006.《致爱妻》
华为新版Datacom认证介绍