nlib
exi/multithread/multithread.cpp

Sample demonstrating the use of (separate) XML parsers in multiple threads.

This implementation uses separate per-thread memory spaces to allow safe, high-speed memory usage by XML parsers. This approach has the advantage that even if the XML parsers running in one of the threads uses up too much memory, the XML parsers in the other threads do not follow suit.

When running this sample in a multi-threaded environment, note the following specific cautions.

/*---------------------------------------------------------------------------*
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