nlib
exi/multithread/multithread.cpp

複数のスレッドで(別個の)XMLパーサーを利用するサンプルです。

XMLパーサーによるメモリ利用を安全かつ高速にするために、スレッド毎に別々のメモリ空間を利用するように実装されています。 どれか1つのスレッドで動作するXMLパーサーがメモリを使いすぎた等の場合でも、他のスレッドのXMLパーサーを道連れにしない、といったメリットがあります。

マルチスレッド環境下で利用する場合、具体的に以下の点に注意するようにしてください。

#include <string.h>
using nlib_ns::threading::Thread;
using nlib_ns::exi::XmlStreamWriter;
using nlib_ns::exi::XmlStreamReader;
using nlib_ns::exi::XmlStreamReaderSettings;
using nlib_ns::exi::ExiAllocator;
#define M(x) NLIB_EXI_UTF8(x)
static void ParseXml(XmlStreamReader* reader) {
while (reader->HasNext()) {
XmlStreamReader::XmlStreamConstants e = reader->Next();
switch (e) {
case XmlStreamReader::START_ELEMENT:
nlib_printf("[thread=%d]: StartElement(%s)\n", tid, M(reader->GetLocalName()));
break;
case XmlStreamReader::END_ELEMENT:
nlib_printf("[thread=%d]: EndElement(%s)\n", tid, M(reader->GetLocalName()));
break;
case XmlStreamReader::CHARACTERS:
nlib_printf("[thread=%d]: Characters(%s)\n", tid, M(reader->GetText()));
break;
default:
break;
}
}
}
static void ThreadA() {
// This thread reads the xml below:
const char myxml[] =
"<?xml version=\"1.0\" encoding=\"UTF-8\" ?>"
"<ROOT>"
" <ITEM1>TEXT1</ITEM1>"
" <ITEM2>"
" <SUB1>TEXT2</SUB1>"
" <SUB2>TEXT3</SUB2>"
" </ITEM2>"
"</ROOT>";
// Initializes the per thread allocator.
void* buffer = malloc(1024 * 128);
if (!buffer) return;
if (ExiAllocator::Init(buffer, 1024 * 128) != 0) return;
// Note that the instances of XmlStreamReader, XmlStreamWriter are not thread-safe.
MemoryInputStream istr(myxml, strlen(myxml));
XmlStreamReaderSettings is;
UniquePtr<XmlStreamReader> r(XmlStreamReader::Create(&istr, is));
if (!r.get()) {
ExiAllocator::Finalize();
free(buffer);
return;
}
ParseXml(r.get());
r->Close();
r.reset(); // You have to delete the objects before you destroy the allocator.
ExiAllocator::Finalize();
free(buffer);
}
static void ThreadB() {
// This thread reads the xml below:
const char myxml[] =
"<?xml version=\"1.0\" encoding=\"UTF-8\" ?>"
"<root>"
" <item1>text1</item1>"
" <item2>"
" <sub1>text2</sub1>"
" <sub2>text3</sub2>"
" </item2>"
"</root>";
// Initializes the per thread allocator.
void* buffer = malloc(1024 * 128);
if (!buffer) return;
if (ExiAllocator::Init(buffer, 1024 * 128) != 0) return;
// Note that the instances of XmlStreamReader, XmlStreamWriter are not thread-safe.
MemoryInputStream istr(myxml, strlen(myxml));
XmlStreamReaderSettings is;
UniquePtr<XmlStreamReader> r(XmlStreamReader::Create(&istr, is));
if (!r.get()) {
ExiAllocator::Finalize();
free(buffer);
return;
}
ParseXml(r.get());
r->Close();
r.reset(); // You have to delete the objects before you destroy the allocator.
ExiAllocator::Finalize();
free(buffer);
}
bool SampleMain(int, char**) {
nlib_printf("Two threads read different XMLs independently\n\n");
Thread thA, thB;
thA.Start(&ThreadA);
thB.Start(&ThreadB);
thA.Join();
thB.Join();
return true;
}
NLIB_MAINFUNC