使用XCB编写X Window程序(06):XCB取代Xlib的理由

  我经常访问Xorg的官网,希望能找到一些对理解Linux和X Window有用的东西。结果也确实是偶有所得。比如,在Xorg的官网中就建议大家不用Xlib了,改用XCB。不可否认,Xlib确实是一个比较老的东西,老到最新的一本关于Xlib的书都已经是N多年前出版的了。有了Xorg官方的指导,我自然不用学Xlib了,直接上XCB。

  经过这一段时间的学习,对XCB有了一定的了解。我的学习是根据XCB官方的教程来的,当然,如果有一点点在GUI编程领域的经验和悟性学习起来会更加事半功倍。在XCB的官方教程中,一开篇就提出XCB比Xlib先进的地方,同时给出一个示例程序证明XCB比Xlib快多少。但是,对于没有一点Xlib和XCB基础的人来说,要理解这个程序确实有点难。但是现在回过头去看这个教程的开头,一切都是那么一目了然。

  XCB取代Xlib大致上有这样一些理由:

  1、Xlib太重量级了,不易转型,而XCB则轻量级得多;

  2、虽然说Xlib是最靠近X协议的底层开发库,但是其实它还不够底层,因为它提供了缓存机制,而XCB没有缓存,一切都是直接操作X协议,比Xlib还要底层;

  3、据说Xlib对新的X扩展支持不好;

  4、Xlib对多线程编程支持不好,虽然它努力过,但是基础没打好,所以怎么努力也干不好这件事,而XCB没有历史负担,适用于多线程编程;

  5、Xlib和X Server的通讯时同步的,而XCB是异步的,所以XCB比Xlib要快得多。

  我这里重点展示第5点。在前面一篇中我对XCB的异步机制有具体的展示。XCB的异步机制其实就是向服务器提交一个请求后,不用等待服务器的答复就可以继续提交后面的请求,因此,不会因为数据在网络上传输的时间而影响程序的效率。而Xlib向X Server提交一个请求后,必须等到服务器答复,才能提交下一个请求。

  下面是一个示例程序,在这个程序中,分别以好的方式和坏的方式使用XCB和Xlib,请求服务器创建500个Atom,比较XCB和Xlib分别花的时间。很幸运,关于Atom上一篇中也提到了,所以不陌生。使用Xlib的坏的方式是一个一个地调用XInternAtom()函数,每次都要等服务器返回后才能创建下一个Atom,所以这是最慢的方式,而使用Xlib的好的方式是使用XInternAtoms()函数一次性创建500个Atom。而使用XCB的坏的方式是,每次调用xcb_intern_atom()函数后,再调用xcb_intern_atom_reply(),确认服务器答复后再创建下一个Atom,很显然这是一个较慢的方式,而且,由于和服务器的一次对话需要调用两个函数,所以使用起来比Xlib还要麻烦。而使用XCB的好的方式,当然是一股脑调用500次xcb_intern_atom()函数,这500次调用完成之后再来关注服务器的答复。示例代码如下,我基本照抄了XCB教程中的代码,只改了最后的几句printf。

  1 /* It‘s a good idea to paste this and other long code examples
  2    into a text editor for easier reading */
  3
  4 #include <stdlib.h>
  5 #include <stdio.h>
  6 #include <string.h>
  7 #include <sys/time.h>
  8 #include <xcb/xcb.h>
  9 #include <X11/Xlib.h>
 10 #define NUM_NAMES 500
 11 /*
 12     NOTE: For concision, we‘re going to be cheesy and use arrays where real code
 13     would use points and memory allocation.s
 14 */
 15 #ifndef __GNUC__
 16 char* strdup(const char* s) {
 17     int n = strlen(s) + 1;
 18
 19     char *dup = malloc(n);
 20
 21     if(dup)
 22         strcpy(dup, s);
 23
 24     return dup;
 25 }
 26 #endif
 27
 28 /*
 29     return interval of time (uses time.h)
 30 */
 31 double
 32 get_time (void) {
 33     struct timeval timev;
 34     gettimeofday(&timev, NULL);
 35     return (double)timev.tv_sec + (((double)timev.tv_usec) / 1000000);
 36 }
 37
 38 /*
 39
 40 */
 41 void
 42 useXlib (char **names,
 43          Display *display ) {
 44
 45     Atom atoms[NUM_NAMES];
 46     for (int i = 0; i < NUM_NAMES; ++i) {
 47         atoms[i] = XInternAtom(display, names[i], 0);
 48     }
 49 }
 50
 51 /*
 52 Request all atoms at once.
 53 */
 54 void
 55 useXlibProperly (char **names,
 56          Display *display ) {
 57
 58     Atom atoms[NUM_NAMES];
 59     if(!XInternAtoms(display, names, NUM_NAMES, 0, atoms))
 60         fprintf(stderr, "XInternAtoms failed\n");
 61 }
 62
 63 /*
 64
 65 */
 66 void
 67 useXCBPoorly (char **names,
 68              xcb_connection_t *connection ) {
 69     xcb_atom_t              atoms[NUM_NAMES];
 70     // in this bad use of xcb, we use the cookie immediately after posting the request with xcb_intern_atom
 71     for (int i = 0; i < NUM_NAMES; ++i) {
 72         /* make request */
 73         xcb_intern_atom_cookie_t cookie = xcb_intern_atom (connection,
 74                                                             0,
 75                                                             strlen(names[i]),
 76                                                             names[i] );
 77         /* get response */
 78         xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply (connection,
 79                                                                 cookie,
 80                                                                 NULL ); // normally a pointer to receive error, but we‘ll
 81
 82 just ignore error handling
 83         if (reply) {
 84             atoms[i] = reply->atom;
 85             free (reply);
 86         }
 87     }
 88     // now we have our atoms (replies), but this is just a demo, so we do nothing with them
 89 }
 90
 91 /*
 92 */
 93 void
 94 useXCBProperly (char **names,
 95                 xcb_connection_t *connection ) {
 96     xcb_atom_t               atoms[NUM_NAMES];
 97     xcb_intern_atom_cookie_t    cookies[NUM_NAMES];
 98     // in this good example, we make all our requests before checking for
 99     // replies because it‘s best to queue requests when we have many at once
100     /* make requests */
101     for (int i = 0; i < NUM_NAMES; ++i) {
102         cookies[i] = xcb_intern_atom (connection,
103                                      0,
104                                      strlen (names[i]),
105                                      names[i] );
106     }
107     /* get responses */
108     for (int i = 0; i < NUM_NAMES; ++i) {
109         xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply (connection,
110                                                                 cookies[i],
111                                                                 NULL ); // normally a pointer to receive errors, but we‘ll
112
113 just ignore error handling
114         if (reply) {
115             atoms[i] = reply->atom;
116             free (reply);
117         }
118     }
119     // now we have our atoms (replies), but this is just a demo, so we do nothing with them
120 }
121
122 int
123 main () {
124     /* setup names for tests */
125     char (**names) = malloc(NUM_NAMES*sizeof(*names));
126     // init names to "NAME0", "NAME1", "NAME2" ... and so on
127     for (int i = 0; i < NUM_NAMES; ++i) {
128         char buf[100];
129         sprintf (buf, "NAME%d", i);
130         names[i] = strdup (buf);
131     }
132
133     /* do tests */
134     double start, XlibTime, XlibGoodTime, XCBBadTime, XCBGoodTime;
135
136     /* test Xlib */
137     Display *display = XOpenDisplay (NULL);
138     start = get_time ();
139     useXlib (names, display);
140     XlibTime = get_time () - start;
141     start = get_time ();
142     useXlibProperly (names, display);
143     XlibGoodTime = get_time () - start;
144     XCloseDisplay (display);
145
146     /* test XCB */
147     xcb_connection_t *connection = xcb_connect (NULL, NULL);
148     start = get_time ();
149     useXCBPoorly (names, connection);
150     XCBBadTime = get_time () - start;
151     start = get_time ();
152     useXCBProperly (names, connection);
153     XCBGoodTime = get_time () - start;
154     xcb_disconnect (connection);
155
156     /* report times */
157     printf ("Bad Xlib time : %f\n", XlibTime);
158     printf ("Good Xlib time : %f\n", XlibGoodTime);
159     printf ("Bad xcb time : %f\n", XCBBadTime);
160     printf ("Good xcb time : %f\n", XCBGoodTime);
161     printf ("ratio of bad xcb time to good xcb time: %f\n", XCBBadTime / XCBGoodTime);
162     printf ("ratio of bad Xlib time to good Xlib time: %f\n", XlibGoodTime / XlibTime);
163     printf ("ratio of bad Xlib time to good XCB time: %f\n", XlibTime / XCBGoodTime);
164     printf ("ratio of good Xlib time to good xcb time: %f\n", XlibGoodTime / XCBGoodTime);
165     return 0;
166 }    

  运行效果如下图:

  从图中可以看出,XCB的异步方式比同步的方式要快几十倍,Xlib好的方式比坏的方式要快100多倍。由于XCB默认就是异步的,而Xlib天生是同步的,所以最好的和最坏的比较,效率相差300多倍。这就是XCB取代Xlib的理由。

(京山游侠于2014-08-01发布于博客园,转载请注明出处。)

使用XCB编写X Window程序(06):XCB取代Xlib的理由,布布扣,bubuko.com

时间: 2024-10-23 03:16:28

使用XCB编写X Window程序(06):XCB取代Xlib的理由的相关文章

使用XCB编写X Window程序(01):快速起步

估计现在已经没有谁使用XCB这么底层的库写应用程序了,要用也是用经过精心封装的Motif, LessTiff, GTK, Qt, EWL,  ETK或者Cairo等高层次的库.我之所以这么费心地去折腾XCB,其实主要也是为了学习.毕竟,使用最接近底层的UI库写代码是学习X协议及GUI编程原理的最好方法. XCB的主要教程可以参考这里:http://xcb.freedesktop.org/tutorial/ 和X协议有关的文档,在这里:http://www.x.org/releases/X11R7

使用XCB编写X Window程序(02):在窗口中绘图

在上一篇中,我展示了怎么连接X服务器以及怎么创建一个窗口.创建窗口是编写GUI程序的根本.在GUI编程中还有另外两个重点,其一是事件处理,其二是在窗口中绘图.这一篇中,将展示如何使用XCB在窗口中进行绘图. 先看一个示例代码及其运行效果,代码如下: 1 #include <stdlib.h> 2 #include <stdio.h> 3 4 #include <xcb/xcb.h> 5 6 int 7 main () 8 { 9 /* geometric objects

使用XCB编写X Window程序(04):在窗口中绘制文字

在前面的几节中,我展示了使用XCB创建窗口.在窗口中画图以及捕获并处理事件.在这一篇中,我将展示在窗口中绘制文字.绘制文字当然离不开字体,所以我还会简单地探讨一下X Server的核心字体系统.老规矩,先上代码和运行效果图,代码如下: 1 #include <stdlib.h> 2 #include <stdio.h> 3 #include <string.h> 4 #include <inttypes.h> 5 #include <xcb/xcb.h

使用XCB编写X Window程序(05):使用异步的方式和X Server通讯及获取和设置窗口的属性

在前面的例子中,我们从来没有关心过调用XCB函数时,该函数和X Server的通讯是同步的还是异步的.因为在前面的例子中,我们基本上不关心XCB函数的返回值,只有在上一篇中,由于某些操作需要关心它们是否成功(比如是否成功打开字体.是否成功创建GC等),才涉及到XCB函数的返回值. 在这一篇中会更进一步,因为是获取窗口的属性,所以肯定要关注从X Server获取的数据,这时,将会涉及到XCB函数同X Server的通讯是同步的还是异步的.什么是同步?就是说调用一个函数向X Server发出一个请求

使用XCB编写X Window程序(06):XCB官方教程中缺少什么

这将是我所写的关于XCB的最后一篇随笔. 在XCB的官方教程中,还有三篇内容,一篇是将Colormap和Pixelmap的,一篇是讲如何更改窗口的鼠标指针的,还有一篇,则是讲如何将Xlib程序转换成xcb程序的.很显然,以上内容都不是我所想要的,所以我就不再一一依葫芦画瓢将它们再写成中文的了(其实理解Colormap和Pixelmap对理解OpenGL很有用).我曾经多次吐槽XCB文档语焉不详,我说它语焉不详是指它对它自己的一些设计理念都没有讲清楚.比如在XCB的示例代码中,大量出现*_iter

用VS2010编写的C++程序,在其他电脑上无法运行,提示缺少mfc100.dll的解决办法

问题: 在自己电脑上用VS2010编写的VC++程序(使用MFC库),不能在其他电脑上运行.双击提示: "无法启动此程序,因为计算机中丢失mfc100.dll 尝试重新安装该程序以解决此问题." 解决方案: 方案一 采用静态编译使用VS2010编译的程序在windowsxp中运行时,经常会出现找不到相关的DLL文件,我们可以使用静态编译的方法把这些运行依赖文件打包到*.exe中来,以减少对环境的依赖. 一般可以配置以下两项: 项目 -< **属性 -< 配置属性-<

1014 编写完词法分析程序的感想

经过几个星期的努力,总算把词法分析的程序给完成了,总的来说这是一个坚苦而又漫长的过程.是啊,读了那么多年的书,编写词法分析程序可是第一次呀!看着劳动成果,很欣慰!虽然这不是我一个人做的,是大家的共同努力得来的. 几个星期前,当听到老师布置给我们的这个题目时,我们都蒙了,这么难的题目我们怎么会啊!毕竟我们对那个一无所知,对于老师上课的讲解还能听懂,不过理论与实践之间还是有鸿沟的.我们私下都表示不满,抗议,可是一切都是徒劳,所以我们只能尽我们自己最大的努力把程序给写出来. “也许完成不了!”两个星期

为编写的Windows程序提升权限

1.要求以管理员身份运行 在vs工程属性中,Linker ---> Manifest File---> UAC Execution Level,选择requireAdministrator (/level='requireAdministrator')选项 2.在main函数开始时运行以下函数代码: BOOL WINAPI EnablePrivileges() { HANDLE hToken; TOKEN_PRIVILEGES tkp; if (!OpenProcessToken(GetCur

java-第四章-机票价格受到淡季旺季的影响,编写的小程序

import java.util.Scanner; public class A02 { /**  * @param args  */ public static void main(String[] args) { // TODO Auto-generated method stub Scanner input = new  Scanner (System.in); System.out.println("请输入月份:1~12"); int choice=input.nextInt(