gtk-gnome-intro.html
来自「linux下gnome编程」· HTML 代码 · 共 999 行 · 第 1/3 页
HTML
999 行
CLASS="PROGRAMLISTING">guint (*GHashFunc) (gconstpointer key);gint (*GCompareFunc) (gconstpointer a, gconstpointer b); </PRE></TD></TR></TABLE><P> As we've seen, GLib's implementation of hash tables is very generic and allows you to declare your own hash and comparison functions. If you are writing your own hashing functions, you should do your best to avoid creating duplicate hash values, in order to keep the buckets from filling up. For example, if your hashing algorithm used only the first four characters of a string-based key, any lookups of keys that started with the same four characters would result in a bucket collision, which would degrade performance of the hash table. Thus a lookup of the key "mythic" would return the same hash value as a lookup of "mythological" and "mythos." Each time you performed a lookup on one of these keys, GLib would have to sift through the linked list of "myth" keys in that bucket. </P><P> To save you the trouble of creating algorithms for the most common types of keys, GLib supplies a handful of prespun hashing functions. You must specify the hashing function when you create the hash table, and you cannot change it later. The GHashTable structure holds the data used by the hash table; you should always use the g_hash_table_* functions to access it. The GHashTable structure is classified as opaque, so you should never access its fields directly. </P><P> Hash tables are neat and pretty efficient, but they do have their limitations. Even though the keys are reduced to integer values, the hash table must cycle through them sequentially when performing lookups. The contents are not sorted, and no guarantees can be made regarding the order of the elements. Lookup times will depend on the hashing function you use, the number of hash collisions in your data set, and the order in which you happened to add the elements. </P><P> The balanced binary tree (GTree) is in a sense a specialized version of a hash table, with its own peculiar quirks. While the hash table is fundamentally an optimized list container, the binary tree is a sorted hierarchical container. Each time you add an element to the binary tree, the tree adjusts itself to make the next lookup operation as efficient as possible. Each node on the tree can have at most two branches (or nodes). Each subnode can in turn have two branches (nodes) of its own, and so on. The tree struggles to keep both sides of every branch balanced. If you add nodes to the left side of a tree, the tree will shuffle things around so that both sides contain a similar number of nodes. </P><P> Thus while the hash table is optimized for faster single key comparisons but may end up traversing an inefficient number of elements for each lookup, the binary tree is optimized for the fewest number of traversals possible. You can customize the way in which the binary tree distributes its nodes by changing the sorting algorithm. </P><P> Although, technically speaking, binary trees have a hierarchical structure, you as a programmer don't explicitly benefit from it. Your lookups are faster, and you have more sorting and traversal options, but you don't really have di- rect control over where your data ends up in the tree. Inserting a new element into a binary tree may trigger a massive shuffling of branches as the tree struggles to rebalance itself. Parents may switch positions with children or move farther down the hierarchy. You can depend on the fact that, for example, a certain element will always remain on the left side of another element, but not how far to the left. </P><P> GNode, GLib's n-ary tree container, gives you this critical control. If you put a GNode at a certain place in the tree, it will stay there until you move it. Furthermore, any element in a GNode tree can have a potentially unlimited number of children or siblings (although each element should only have one parent). In a sense, the GNode is similar to a two-dimensional doubly linked list, in which you can iterate from sibling to sibling and from parent to child (see Figure 2.3). </P><DIVCLASS="FIGURE"><ANAME="AEN114"></A><P><B>Figure 2-3. Structure of an N-ary Tree</B></P><DIVCLASS="MEDIAOBJECT"><P><IMGSRC="figures/2f3.png"></IMG></P></DIV></DIV><P> We've covered a lot of ground in this section without showing a single scrap of useful container code. You may not have learned much about how to write code for GLib's many containers, but hopefully you now have a better idea of how they work. This should make it much easier to understand the containers' APIs. The online GLib documentation covers all of this in much greater detail. </P></DIV><DIVCLASS="SECT2"><H2CLASS="SECT2"><ANAME="AEN120">Other Toys</A></H2><P> GLib isn't just a reservoir for data containers and portability wrappers. It also harbors a surprising range of useful tools and utilities. Not only does it provide generic abstractions for threads, dynamically loaded modules, and input/output handling, but it also contains such gems as a full-featured event loop (used extensively by GTK+) and a lexical scanner for parsing through text streams. </P><P> Thread handling is a very complicated affair, far beyond the scope of this book. We'll touch on it only lightly here. GLib's thread implementation is by no means comprehensive, or particularly advanced; in fact, it is only just enough to make GLib thread-safe. It covers the basics in a clear, simple manner, providing thread synchronization through mutexes (GMutex and GStaticMutex) and thread-local data (GPrivate and GStaticPrivate), al- though at this time it does not contain functions to create and destroy the threads. You'll have to use your operating system's thread API directly for that. GLib's GThread implementation resides in a standalone library, libgthread, and is more or less just a wrapper around the native thread library-for example, libpthread. </P><P> GLib's GModule interface provides a portable wrapper around the dynamic module-loading APIs of most modern operating systems, including Linux, Solaris, IRIX, HP/UX, and even Microsoft Windows (as DLL, Dynamic Link Library, files). You can use it to load in libraries at runtime-for example, as part of a plug-in architecture, like the countless graphics filters in the GIMP drawing application. Using the GModule functions, you can load up a dynamic module, search for specific functions inside it, invoke those functions, and then close the module. GModule insulates you from the often vast differences in dynamic loading between platforms and leads to more portable code. Like GThread, the GModule implementation resides in its own library, libgmodule. </P><P> GLib also contains a handful of dynamic memory management functions, in the form of wrappers around the standard C memory functions. You can use g_new( ) and g_malloc( ) to freshly allocate memory, g_new0( ) and g_malloc0( ) to allocate memory initialized to zeros, and g_renew( ) and g_realloc( ) to reallocate existing memory to a different size. The g_free( ) function cleans up the memory, regardless of which GLib function you used to allocate it. The optional functions g_mem_profile( ) and g_mem_check( ) provide you with feedback on the currently allocated memory, although since these functions introduce a performance penalty, you'll have to compile your version of GLib with the configure script options --enable-mem-profile and --enable-mem-check to use them. </P><P> If you plan on allocating and freeing lots of small chunks of memory, you might want to look into GLib's block memory support. GMemChunk allocates a single chunk of memory to store many smaller, contiguous objects. It handles the memory management for you, keeping track of which chunks are in use and which chunks have been freed. When you request a new chunk of memory, GMemChunk gives you a pointer to an existing slice of its larger block, rather than allocating new memory with the more costly call to g_malloc( ). GLib uses GMemChunk internally, for its linked list and GNode data containers. </P><P> The GIOChannel interface is a wrapper around standard UNIX files, sockets, and pipes that brings consistency and portability to the methods you use to handle these file descriptors. GIOChannel also helps integrate input/output polling and callbacks into GLib's event loop. This feature will come in handy if your application needs to periodically check on a socket or pipe connection without blocking each time (which would interfere with your application's repainting and responsiveness), or monitor a file for changes. You'll have to create the file descriptor yourself (unless you're using stdin, stdout, or stderr), but once you wrap it in a GIOChannel, you can use GLib to wire it into the event loop for callback notifications, to read and write from it, and to close it when you're done. GIOChannel also supports reference counting, in case you need to share a channel with more than one object. </P><P> The GMainLoop event loop is the heartbeat of most GTK+ and GNOME applications. The event loop cycles continuously through its iterations, nudging all the various hooks and event streams you've installed into it. The event loop is like a many-armed conductor sitting at the center of your application, letting you know when important things happen. You can set up polling events based on file descriptors (e.g., with GIOChannel), timers to synthesize periodic events, and even generic event sources (like the GDK event queue). You can also prioritize your event sources so that, for example, a certain socket event takes priority over certain timer events. If you have any low-priority maintenance routines that you want to run in the background, you can install them as idle handlers in the event loop. When the event loop runs out of events, it will spend its time running the idle functions. GMainLoop is ex- tremely versatile and can be used in virtually any event-driven software. It was originally part of GTK+, but later it was abstracted and pulled into GLib to make it available to applications outside of GTK+. </P><P> Moving along, the lexical scanner, GScanner, is a generic, configurable text-parsing tool. It's good for reading in configuration files, which is exactly what GTK+ uses it for. GTK+ reads in a text-based gtkrc file each time you start up an application; the user can define the appearance and behavior of GTK+ in the gtkrc file. GScanner recognizes a wide assortment of common tokens, like curly braces, numbers, characters, commas, and even various styles of comments. You can also define custom symbols, or tokens, if the basic set doesn't cover your needs. By tweaking the contents of the GScannerConfig structure and passing it on to GScanner, you can exert very fine control over which tokens the lexical scanner will acknowledge and how it reacts to different combinations of tokens. Once the GScanner is set up, you can repeatedly call the g_scanner_get_next_token ( ) function to grab tokens one at a time until you're finished, or until you reach the end of the file. GLib's lexical scanner is surprisingly powerful for such a small, rarely used bit of code. The interface is admittedly a little cryptic, and the documentation is a bit thinner than it could be, but it's quite easy to use once you grasp how it works. For a working example, take a look at the file gtk+/gtk/gtkrc.c in the GTK+ source code distribution. </P><P> Future versions of GTK+, starting with GTK+ 2.0, will contain the GObject infrastructure, for managing object-oriented systems. GObject is essentially the GTK+ object system ripped out of GTK+ and made available to non-GTK+ applications, much as the GTK+ main loop was extracted and put into GMainLoop. </P></DIV></DIV></DIV><DIVCLASS="NAVFOOTER"><HRALIGN="LEFT"WIDTH="100%"><TABLEWIDTH="100%"BORDER="0"CELLPADDING="0"CELLSPACING="0"><TR><TDWIDTH="33%"ALIGN="left"VALIGN="top"><AHREF="acknowledgements.html">Prev</A></TD><TDWIDTH="34%"ALIGN="center"VALIGN="top"><AHREF="index.html">Home</A></TD><TDWIDTH="33%"ALIGN="right"VALIGN="top"><AHREF="gdk.html">Next</A></TD></TR><TR><TDWIDTH="33%"ALIGN="left"VALIGN="top">Acknowledgments</TD><TDWIDTH="34%"ALIGN="center"VALIGN="top"> </TD><TDWIDTH="33%"ALIGN="right"VALIGN="top">GDK</TD></TR></TABLE></DIV></BODY></HTML>
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?