xmlInitParser和xmlCleanupParser 多线程操作

14 篇文章 0 订阅

使用libxml2库的朋友,可能会对它提供的初始化接口(xmlInitParser )和清除资源接口(xmlCleanupParser )感到困惑.因为在它主页中提供的例子里面,各处使用的情况差别很大. 我花了些时间把这两个接口使用方法整理如下:

1. 在单线程(single-threaded)环境中

   xmlInitParser 可以被调用一次,或者被调用多次(多于一次),甚至可以不被调用.

   对于第一种情况,很容易理解,因为接口作用是初始化,而且应该在程序的入口处调用. 这也是推荐的使用方法.

   对于第二种情况,看其接口的实现代码就很容易理解,第二次以后的调用只是判断完标志位后简单地返回.

   --------------------------------------------------------------------------------

   void xmlInitParser(void) {
    if (xmlParserInitialized != 0)
        return;

   //do initialization for xml library
   …

    xmlParserInitialized = 1;
   }

   --------------------------------------------------------------------------------

   对于第三种情况,在作者在mailing list的回答中可找到答案,而且这一点我也已经简单地通过例子验证过.而且在libmxl2自带的很多sample中,都是属于这样的情况.

   --------------------------------------------------------------------------------

   http://mail.gnome.org/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()也可以被调用一次,或者被调用多次(多于一次),甚至可以不被调用.

    对于第一种情况,很容易理解,因为接口作用是清除资源的, 而且应该在程序的出口处调用. 这也是推荐的使用方法.

   对于第二种情况,看其接口的实现代码就很容易理解,第二次以后的调用只是判断完标志位后简单地返回.

   --------------------------------------------------------------------------------

  void xmlCleanupParser(void) {

    if (!xmlParserInitialized)
        return;
 
     // do cleanup for xml library
   …
 
    xmlParserInitialized = 0;

   }

   --------------------------------------------------------------------------------

   对于第三种情况,这样的使用方法不会对程序造成任何的破坏,但是在xmlInitParser()中分配的部分内存将一直被占用,直至整个程序退出.所以这是一种不会产生影响但也不推荐的使用方法.

2. 在多线程(multi-threaded)环境中

   在多线程环境下,使用它们要比单线程环境下面需要注意更多的问题.

   使用xmlInitParser()必须遵循一下两个原则:

   (1) xmlInitParser()不能在线程中被调用,因为xmlInitParser()不是原子操作,可能会引起线程竞争,导致程序意外.

   (2) xmlInitParser()应该在主线程中被调用,在开始任何线程之前,在程序的入口处.

   从原则上如果整个程序中不调用xmlInitParser()在某些情况是可以的,因为上一节提到,调用任何其他libxml2 API时会检验是否已经初始化,如果没有,将自动进行初始化. 但是如果在整个开始线程之前的进程中都没有调用到libxml2 的任何API,而是在线程开始调用libxml2的API,就会出现初始化时线程竞争的糟糕事情.所以这是非常不推荐的做法.

   当然,在进程(线程开始前)多次调用xmlInitParser()不会产生问题,因为第二次以后的调用只是简单地检查标志位接下来返回.

   使用xmlCleanupParser()必须遵循一下两个原则:

   (1) xmlCleanupParser()不能在线程中被调用,因为先结束的进程会把共享内存清除,接下来尚未结束的的线程就无法正确访问.

   (2) xmlCleanupParser()应该在主线程中被调用,在不再使用libxml2库时,一般在程序的出口处.

   这里需要注意一个问题,如果你无法确定其他用户是否还在使用libxml2库,那么就不要调用xmlCleanupParser(),因为这样最差的情况是浪费了一块内存,直至在程序结束时才能被收回,比起程序崩溃,这样的代价还是值得的.在mailing list中,作者也提到这样的方案.

   同样,在进程(所有进程结束之后)多次调用xmlCleanupParser()不会对程序产生任何影响,第二次以后的调用仅是检查标志位和简单第返回.

   在多线程环境下,推荐的使用方法是:

   ------------------------------------------------------------------------------

  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;

 }  

 ------------------------------------------------------------------------------ 

以上是我总结的在单线程和多线程环境下使用xmlInitParser()和xmlCleanupParser()时需要注意的几点,欢迎大家补充

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在 C 语言中,可以使用 libxml2 库中提供的函数将结构体和 XML 互相转换。下面是一个简单的示例: 假设有一个结构体定义如下: ```c typedef struct { int id; char name[20]; int age; } Person; ``` 我们可以将这个结构体转换为 XML 的格式,如下所示: ```xml <Person> <id>1</id> <name>John</name> <age>30</age> </Person> ``` 以下是将这个结构体转换为 XML 的代码示例: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <libxml/parser.h> #include <libxml/tree.h> typedef struct { int id; char name[20]; int age; } Person; xmlNodePtr create_person_node(xmlDocPtr doc, Person *person) { xmlNodePtr node = xmlNewNode(NULL, "Person"); char buf[32]; xmlNewChild(node, NULL, "id", snprintf(buf, sizeof(buf), "%d", person->id), NULL); xmlNewChild(node, NULL, "name", person->name, NULL); xmlNewChild(node, NULL, "age", snprintf(buf, sizeof(buf), "%d", person->age), NULL); return node; } int main() { Person person = {1, "John", 30}; xmlDocPtr doc = xmlNewDoc(BAD_CAST "1.0"); xmlNodePtr root_node = xmlNewNode(NULL, "Root"); xmlDocSetRootElement(doc, root_node); xmlNodePtr person_node = create_person_node(doc, &person); xmlAddChild(root_node, person_node); xmlChar *xml_buf = NULL; int xml_size = 0; xmlDocDumpFormatMemory(doc, &xml_buf, &xml_size, 1); printf("XML:\n%s\n", (char *)xml_buf); xmlFree(xml_buf); xmlFreeDoc(doc); xmlCleanupParser(); return 0; } ``` 而将 XML 转换为结构体的过程,则需要将读取到的 XML 节点的值依次赋值给结构体的成员变量。以下是将 XML 转换为结构体的代码示例: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <libxml/parser.h> #include <libxml/tree.h> typedef struct { int id; char name[20]; int age; } Person; Person *create_person_from_node(xmlNodePtr node) { Person *person = (Person *)malloc(sizeof(Person)); memset(person, 0, sizeof(Person)); for (xmlNodePtr cur = node->children; cur != NULL; cur = cur->next) { if (cur->type != XML_ELEMENT_NODE) { continue; } if (xmlStrcmp(cur->name, (const xmlChar *)"id") == 0) { person->id = atoi((const char *)xmlNodeGetContent(cur)); } else if (xmlStrcmp(cur->name, (const xmlChar *)"name") == 0) { strncpy(person->name, (const char *)xmlNodeGetContent(cur), sizeof(person->name) - 1); } else if (xmlStrcmp(cur->name, (const xmlChar *)"age") == 0) { person->age = atoi((const char *)xmlNodeGetContent(cur)); } } return person; } int main() { const char *xml_str = "<Root><Person><id>1</id><name>John</name><age>30</age></Person></Root>"; xmlDocPtr doc = xmlReadMemory(xml_str, strlen(xml_str), "noname.xml", NULL, 0); xmlNodePtr root_node = xmlDocGetRootElement(doc); for (xmlNodePtr cur = root_node->children; cur != NULL; cur = cur->next) { if (cur->type != XML_ELEMENT_NODE) { continue; } Person *person = create_person_from_node(cur); printf("Person: id=%d, name=%s, age=%d\n", person->id, person->name, person->age); free(person); } xmlFreeDoc(doc); xmlCleanupParser(); return 0; } ``` 以上是一个简单的将结构体和 XML 互相转换的示例,具体实现可以根据实际情况进行修改和扩展。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值