码迷,mamicode.com
首页 > Windows程序 > 详细

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

时间:2014-08-01 23:06:02      阅读:2523      评论:0      收藏:0      [点我收藏+]

标签:style   blog   http   color   使用   os   io   数据   

   我经常访问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 }    


  运行效果如下图:

bubuko.com,布布扣

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

 

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

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

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

标签:style   blog   http   color   使用   os   io   数据   

原文地址:http://www.cnblogs.com/youxia/p/gui006.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!