nlib
exi/multithread/multithread.cpp

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

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

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

/*---------------------------------------------------------------------------*
Project: CrossRoad
Copyright (C)2012-2016 Nintendo. All rights reserved.
These coded instructions, statements, and computer programs contain
proprietary information of Nintendo of America Inc. and/or Nintendo
Company Ltd., and are protected by Federal copyright law. They may
not be disclosed to third parties or copied or duplicated in any form,
in whole or in part, without the prior written consent of Nintendo.
*---------------------------------------------------------------------------*/
#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