|
使用libxml2庫的朋友,可能會對它提供的初始化接口(xmlInitParser )和清除資源接口(xmlCleanupParser )感到困惑.因?yàn)樵谒黜撝刑峁┑睦永锩?各處使用的情況差別很大. 我花了些時(shí)間把這兩個(gè)接口使用方法整理如下: 1. 在單線程(single-threaded)環(huán)境中 xmlInitParser 可以被調(diào)用一次,或者被調(diào)用多次(多于一次),甚至可以不被調(diào)用. 對于第一種情況,很容易理解,因?yàn)榻涌谧饔檬浅跏蓟?而且應(yīng)該在程序的入口處調(diào)用. 這也是推薦的使用方法. 對于第二種情況,看其接口的實(shí)現(xiàn)代碼就很容易理解,第二次以后的調(diào)用只是判斷完標(biāo)志位后簡單地返回. -------------------------------------------------------------------------------- void xmlInitParser(void) { //do initialization for xml library xmlParserInitialized = 1; -------------------------------------------------------------------------------- 對于第三種情況,在作者在mailing list的回答中可找到答案,而且這一點(diǎn)我也已經(jīng)簡單地通過例子驗(yàn)證過.而且在libmxl2自帶的很多sample中,都是屬于這樣的情況. -------------------------------------------------------------------------------- http://mail./archives/xml/2003-May/msg00027.html Q: 1. If I *don't* use libxml2's thread-support do I have to call xmlInitParser() only once per application or once per parsing? A: You don't even need to call it. It's done automatically, it's just better to do it explicitly in a thread environment. --------------------------------------------------------------------------------
類似于xmlInitParser(), xmlCleanupParser()也可以被調(diào)用一次,或者被調(diào)用多次(多于一次),甚至可以不被調(diào)用. 對于第一種情況,很容易理解,因?yàn)榻涌谧饔檬乔宄Y源的, 而且應(yīng)該在程序的出口處調(diào)用. 這也是推薦的使用方法. 對于第二種情況,看其接口的實(shí)現(xiàn)代碼就很容易理解,第二次以后的調(diào)用只是判斷完標(biāo)志位后簡單地返回. -------------------------------------------------------------------------------- void xmlCleanupParser(void) { if (!xmlParserInitialized)
return;
// do cleanup for xml library
…
xmlParserInitialized = 0;
} -------------------------------------------------------------------------------- 對于第三種情況,這樣的使用方法不會對程序造成任何的破壞,但是在xmlInitParser()中分配的部分內(nèi)存將一直被占用,直至整個(gè)程序退出.所以這是一種不會產(chǎn)生影響但也不推薦的使用方法.
2. 在多線程(multi-threaded)環(huán)境中 在多線程環(huán)境下,使用它們要比單線程環(huán)境下面需要注意更多的問題. 使用xmlInitParser()必須遵循一下兩個(gè)原則: (1) xmlInitParser()不能在線程中被調(diào)用,因?yàn)閤mlInitParser()不是原子操作,可能會引起線程競爭,導(dǎo)致程序意外. (2) xmlInitParser()應(yīng)該在主線程中被調(diào)用,在開始任何線程之前,在程序的入口處. 從原則上如果整個(gè)程序中不調(diào)用xmlInitParser()在某些情況是可以的,因?yàn)樯弦还?jié)提到,調(diào)用任何其他libxml2 API時(shí)會檢驗(yàn)是否已經(jīng)初始化,如果沒有,將自動(dòng)進(jìn)行初始化. 但是如果在整個(gè)開始線程之前的進(jìn)程中都沒有調(diào)用到libxml2 的任何API,而是在線程開始調(diào)用libxml2的API,就會出現(xiàn)初始化時(shí)線程競爭的糟糕事情.所以這是非常不推薦的做法. 當(dāng)然,在進(jìn)程(線程開始前)多次調(diào)用xmlInitParser()不會產(chǎn)生問題,因?yàn)榈诙我院蟮恼{(diào)用只是簡單地檢查標(biāo)志位接下來返回.
使用xmlCleanupParser()必須遵循一下兩個(gè)原則: (1) xmlCleanupParser()不能在線程中被調(diào)用,因?yàn)橄冉Y(jié)束的進(jìn)程會把共享內(nèi)存清除,接下來尚未結(jié)束的的線程就無法正確訪問. (2) xmlCleanupParser()應(yīng)該在主線程中被調(diào)用,在不再使用libxml2庫時(shí),一般在程序的出口處. 這里需要注意一個(gè)問題,如果你無法確定其他用戶是否還在使用libxml2庫,那么就不要調(diào)用xmlCleanupParser(),因?yàn)檫@樣最差的情況是浪費(fèi)了一塊內(nèi)存,直至在程序結(jié)束時(shí)才能被收回,比起程序崩潰,這樣的代價(jià)還是值得的.在mailing list中,作者也提到這樣的方案. 同樣,在進(jìn)程(所有進(jìn)程結(jié)束之后)多次調(diào)用xmlCleanupParser()不會對程序產(chǎn)生任何影響,第二次以后的調(diào)用僅是檢查標(biāo)志位和簡單第返回. 在多線程環(huán)境下,推薦的使用方法是: ------------------------------------------------------------------------------ int main ( int argc, char **argv )
{
//do library initialization at the beginning of the program
xmlInitParser();
//do other program initialization
…
//start thread
for (i = 0; i < num_threads; i++) {
ret = pthread_create
…
}
//do other program initialization
…
//do library cleanup when the program ends up
xmlCleanupParser(();
return 0;
} |
|
|