日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

淺析GLib

 renhl252 2015-01-09

在 IBM Bluemix 云平臺上開發(fā)并部署您的下一個應(yīng)用。

現(xiàn)在就開始免費試用

GLib需要一個支持線程的操作系統(tǒng)和一個字符集間轉(zhuǎn)換函數(shù)iconv的支持,事實上大多現(xiàn)代的操作系統(tǒng)都有以上兩項功能。

GLib由基礎(chǔ)類型、對核心應(yīng)用的支持、實用功能、數(shù)據(jù)類型和對象系統(tǒng)五個部分組成的。

GLib的最新版本是GLib2.2.1,可以到www.gtk.org網(wǎng)站下載其源代碼。使用GLib2.0編寫的應(yīng)用程序,在編譯時應(yīng)該在編譯命令中加入`pkg-config -cflags -libs glib-2.0`,如編譯一個名為hello.c的程序,輸出名為hello的可執(zhí)行文件,則命令為:

gcc `pkg-config -cflags -libs glib-2.0`  hello.c -o hello

在GLIB中將線程(gthread),插件(gmoudle)和對象系統(tǒng)(gobject)這三個子系統(tǒng)區(qū)別對待,編譯時要注意加入相應(yīng)的參數(shù)。

如程序中用到對象系統(tǒng),編譯時就應(yīng)加入:

`pkg-config --cflags --libs gobject-2.0`

用到線程,編譯時則加入:

`pkg-config --cflags --libs gthread-2.0`

用到插件,編譯時則加入:

`pkg-config --cflags --libs gmoudle-2.0`

基礎(chǔ)類型

GLib的基礎(chǔ)是由基礎(chǔ)類型、范圍限定宏、標準宏、類型轉(zhuǎn)換宏、字節(jié)次序變換宏、數(shù)學常數(shù)定義和雜項宏等各項組成的。這里主要介紹基礎(chǔ)類型,因為它們遍及與GLIB相關(guān)的各種程序庫和軟件包中,如GTK+,GNOME,MONO等大的開源項目。

基礎(chǔ)類型又稱標準類型,GLib將C語言中的數(shù)據(jù)類型統(tǒng)一封裝成自己的數(shù)據(jù)類型,均以小寫字母'g'開頭,如:gpointer是指針類型(void *)、guint是無符號整型(unsigned int)等,其中有一些是修飾性的,如:gint、gchar等,它們和C語言中的int、char是完全相同的。這些數(shù)據(jù)類型使用起來和C語言中的數(shù)據(jù)類型完全一樣,當你熟悉了以后會發(fā)現(xiàn)它們的使用方法更靈活,更直觀也更易于理解一些。當然你可以把C語言中的數(shù)據(jù)類型直接拿來使用,這絲毫不影響你編寫程序的編譯。

另外范圍限定宏和類型轉(zhuǎn)換宏也較常用,如G_MAXINT表示最大的int型值,用宏GINT_TO_POINTER(i)將整型變量i轉(zhuǎn)換為指針型,宏GPOINTER_TO_INT(p)將指針型變量p轉(zhuǎn)換為整型。

邏輯類型gboolean的值TRUE和FALSE是在常數(shù)宏中定義的,另外還包括G_E表示自然對數(shù),G_PI表示圓周率,G_PI_2表示圓周率的1/2等一些數(shù)學常數(shù)。

回頁首

對核心應(yīng)用的支持

GLib對核心應(yīng)用的支持包括事件循環(huán)、內(nèi)存操作、線程操作、動態(tài)鏈接庫的操作和出錯處理與日志等。

下面代碼演示了事件循環(huán)、內(nèi)存操作、線程這三種功能的簡單應(yīng)用:

#include <glib.h>
static GMutex *mutex = NULL;
static gboolean t1_end = FALSE;
static gboolean t2_end = FALSE;
typedef struct _Arg Arg;
struct _Arg
{
	GMainLoop* loop;
	gint max;
};
void	run_1(Arg *arg)
{
	int i ;
	
	for(i=0; i<arg->max; i++)
	{
		if(g_mutex_trylock(mutex) == FALSE)
		{
			//g_print("%d : thread 2 locked the mutex \n", i);
			g_print("%d :線程2鎖定了互斥對象\n", i);
			g_mutex_unlock(mutex);
		}
		else
		{
			g_usleep(10);
		}
	}
	t1_end = TRUE;
}
void	run_2(Arg *arg)
{
	int i;
	for(i=0; i<arg->max; i++)
	{
		if(g_mutex_trylock(mutex) == FALSE)
		{
			//g_print("%d : thread 1 locked mutex \n", i);
			g_print("%d :線程1鎖定了互斥對象\n", i);
			g_mutex_unlock(mutex);
		}
		else
		{
			g_usleep(10);
		}
	}
	t2_end = TRUE;
}
void run_3(Arg *arg)
{
	for(;;)
	{
		if(t1_end && t2_end)
		{
			g_main_loop_quit(arg->loop);
			break;
		}
	}
}
int	main(int argc, char *argv[])
{
	GMainLoop *mloop;
	Arg *arg;
	
	if(!g_thread_supported())
		g_thread_init(NULL);
	mloop = g_main_loop_new(NULL, FALSE);
	
	arg = g_new(Arg, 1);
	arg->loop = mloop;
	arg->max = 11;
		
	mutex = g_mutex_new();
	g_thread_create(run_1, arg, TRUE, NULL);
	g_thread_create(run_2, arg, TRUE, NULL);
	g_thread_create(run_3, arg, TRUE, NULL);
	
	g_main_loop_run(mloop);
	g_print("線程3退出事件循環(huán)\n");
	g_mutex_free(mutex);
	g_print("釋放互斥對象\n"); 
	g_free(arg);
	g_print("釋放參數(shù)所用的內(nèi)存\n");
}

Makefile文件如下:

CC = gcc
all:
	$(CC) `pkg-config --cflags --libs glib-2.0 gthread-2.0` loop.c -o loop

下面為輸出結(jié)果:

0 :線程1鎖定了互斥對象
1 :線程2鎖定了互斥對象
2 :線程1鎖定了互斥對象
3 :線程2鎖定了互斥對象
4 :線程1鎖定了互斥對象
5 :線程2鎖定了互斥對象
6 :線程1鎖定了互斥對象
7 :線程2鎖定了互斥對象
8 :線程1鎖定了互斥對象
9 :線程2鎖定了互斥對象
10 :線程1鎖定了互斥對象
線程3退出事件循環(huán)
釋放互斥對象
釋放參數(shù)所用的內(nèi)存

以上例程創(chuàng)建了三個線程,其中run_1和run_2操作互斥對象,run_3檢索前兩個線程是否結(jié)束,如結(jié)束的話,則執(zhí)行g(shù)_main_loop_quit退出事件循環(huán)。由于線程的運行是不確定的,所以不一定每次都是這一輸出結(jié)果。

首先定義一個結(jié)構(gòu)類型來保存創(chuàng)建的事件循環(huán)的對象指針和線程運行時的最多循環(huán)次數(shù),一般情況下,如果為此數(shù)據(jù)結(jié)構(gòu)來分配內(nèi)存的話,用Arg *arg = (Arg *)malloc(sizeof(Arg));,釋放時用free(arg);,這種傳統(tǒng)的做法曾經(jīng)讓很多C語言的初學者頭痛,尤其是需要多次操作的時候,GLib中提供了類似的函數(shù)g_malloc和g_free,最好用的方法是其將g_malloc函數(shù)封裝成了宏g_new,這個宏有兩個參數(shù),第一個是結(jié)構(gòu)類型,第二個是要分配結(jié)構(gòu)的數(shù)量,這段代碼中只用到了一個Arg數(shù)據(jù)結(jié)構(gòu),所以是g_new(Arg, 1)。在程序結(jié)束時用g_free來釋放。

在線程初始化時,首先是判斷線程是否初始化的函數(shù)g_thread_supported,如果其返回FALSE則表明線程并未初始化,這時必須用g_thread_init來初始化,這是較明智的做法。

事件循環(huán)GMainLoop在用g_main_loop_new創(chuàng)建之后并不馬上運行,用g_main_loop_run運行后,還要用g_main_loop_quit退出,否則循環(huán)將一直運行下去,這兩個函數(shù)的參數(shù)都是GMainLoop型的指針,在主函數(shù)中并未直接運行g(shù)_main_loop_quit,而是把它放在線程的函數(shù)中了,這一點需讀者注意。

回頁首

實用功能

GLib中包含了近二十種實用功能,從簡單的字符處理到初學者很難理解的XML解析功能,這里介紹兩種較簡單的:隨機數(shù)和計時。

下面代碼演示如何產(chǎn)生1-100之間的隨機整數(shù)和演示如何計算30000000次累加在計算時用的時間:

/* until.c 用來測試實用功能 */
#include <glib.h>
int	main(int argc, char *argv[])
{
	GRand *rand;
	GTimer *timer;
	
	gint n;
	gint i, j;
	gint x = 0;
	rand = g_rand_new();	//創(chuàng)建隨機數(shù)對象
	for(n=0; n<20; n++)
	{	//產(chǎn)生隨機數(shù)并顯示出來
		g_print("%d\t",g_rand_int_range(rand,1,100));
	}
	g_print("\n");
	g_rand_free(rand);	//釋放隨機數(shù)對象
	//創(chuàng)建計時器
	timer = g_timer_new();
	g_timer_start(timer);//開始計時
	for(i=0; i<10000; i++)
		for(j=0; j<3000; j++)
			x++;//累計
	g_timer_stop(timer);//計時結(jié)束
	//輸出計時結(jié)果
	g_print("%ld\tall:%.2f seconds was used!\n",x,g_timer_elapsed(timer,NULL));
}

Makefile文件內(nèi)容如下:

CC = gcc all: $(CC) `pkg-config --cflags --libs glib-2.0 ` until.c -o until

輸出結(jié)果:

48 95 95 99 90 24 90 29 78 4 53 87 1 86 7 93 57 88 75 4
30000000 all:1.47 seconds was used!

GLIB中的每個對象幾乎都有一個或多個*_new函數(shù)來創(chuàng)建,計時器GTimer和隨機器GRand也一樣,也都有相對應(yīng)的函數(shù)來結(jié)束對象的使用,如GTimer的g_timer_stop和GRand的g_rand_free。

這可能是GLIB實用功能中最簡單的兩種了,許多朋友會一目了然。我們還應(yīng)注意到GLIB的代碼風格和封裝技巧是具有獨到之處的,這種風格和技巧足以讓一些自稱簡潔實用的SDK汗顏,學習掌握這一風格可能會讓我們受益匪淺。

回頁首

數(shù)據(jù)類型

GLib中定義了十幾種常用的數(shù)據(jù)結(jié)構(gòu)類型和它們的相關(guān)操作函數(shù),下面是關(guān)于字符串類型的簡單示例:

#include <glib.h>
int	main(int argc, char *argv[])
{
	GString *s;
	s = g_string_new("Hello");
	g_print("%s\n", s->str);
	s = g_string_append(s," World!");
	g_print("%s\n",s->str);
	s = g_string_erase(s,0,6);
	g_print("%s\n",s->str);
	s = g_string_prepend(s,"Also a ");
	g_print("%s\n",s->str);
	
	s = g_string_insert(s,6," Nice");
	g_print("%s\n",s->str);
}

Makefile文件如下:

	CC = gcc
all:
	$(CC) `pkg-config --cflags --libs glib-2.0 ` string.c -o str

下面是輸出結(jié)果:

Hello
Hello World!
World!
Also a World!
Also a Nice World!

字符串在編程中出現(xiàn)頻率之高,即使是初學者也很清楚,追加、刪除和插入等常用操作理解后,還可以進一步了解掌握其它更復雜的操作。

GLib提供了一種內(nèi)存塊(GMemChunk)數(shù)據(jù)類型,它為分配等大的內(nèi)存區(qū)提供了一種非常好用的操作方式,下面程序演示了內(nèi)存塊數(shù)據(jù)類型的簡單用法:

#include <glib.h>
int	main(int argc, char *argv[])
{
	GMemChunk *chunk;	//定義內(nèi)存塊
	gchar *mem[10];	//定義指向原子的指針數(shù)組
	gint i, j;
	//創(chuàng)建內(nèi)存塊
	chunk = g_mem_chunk_new("Test MemChunk", 5, 50, G_ALLOC_AND_FREE);
				//名稱,原子的長度, 內(nèi)存塊的長度,類型
	for(i=0; i<10; i++)
	{
		//創(chuàng)建對象
		//mem[i] = g_chunk_new(gchar, chunk);
		mem[i] = (gchar*)g_mem_chunk_alloc(chunk);
		for(j=0; j<5; j++)
		{
			mem[i][j] = 'A' + j;//為內(nèi)存塊中的指針賦值
		}
	}
	
	g_mem_chunk_print(chunk);	//顯示內(nèi)存塊信息
	for(i=0; i<10; i++)
	{
		g_print("%s\t",mem[i]);//顯示內(nèi)存塊中的內(nèi)容
	}
	
	for(i=0; i<10; i++)
	{
		g_mem_chunk_free(chunk,mem[i]); //釋放所有分配的內(nèi)存
	}
	g_mem_chunk_destroy(chunk);
}

Makefile文件件如下:

CC = gcc
all:
	$(CC) `pkg-config --cflags --libs glib-2.0` data1.c -o data1

以下為輸出結(jié)果:

GLib-INFO: Test MemChunk: 80 bytes using 2 mem areas
ABCDE	ABCDE	ABCDE	ABCDE	ABCDE	ABCDE	ABCDE	ABCDE	ABCDE	ABCDE

這里說明這一數(shù)據(jù)類型的原因是通過它可以他細體會內(nèi)存分配這一運行時處理環(huán)節(jié)的應(yīng)用之妙。

我們在程序中分配的是50字節(jié)的空間,而實際用的是80字節(jié),由此可以看出其在分配內(nèi)存時本身用到了部分內(nèi)存空間。

從上面的示例代碼中可以看出,在GLib中幾乎所有的對象都是C語言的結(jié)構(gòu)類型,一般命名以大寫字母G開頭的單詞,如GList表示雙向鏈表,所有與之相關(guān)的操作函數(shù)都以小寫的字母g加下劃線加小寫的單詞加下劃線開頭,如以g_list_*開頭的函數(shù)都是與這相關(guān)的操作函數(shù),而且這些函數(shù)中的第一個參數(shù)多數(shù)是此對象的指針。

GLIB中的數(shù)據(jù)類型在GLIB本身,尤其是GTK+中頻繁用到,了解掌握這些數(shù)據(jù)類據(jù)類型的用法是非常必要的,這對進一步靈活開發(fā)GTK+程序來說是關(guān)鍵一環(huán),而且是對大學中的《數(shù)據(jù)結(jié)構(gòu)》一科的很好回顧。

在下一篇GOBJECT對象系統(tǒng)中將詳細介紹GLIB中最重要的組成部分GOBJECT系統(tǒng),希望這一由C語言組建的單繼承的對象系統(tǒng)會幫助你走進GTK+的世界。

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多