| xlsgen > overview > Multi-core sample |
xlsgen supports multiple threads, one thread per document. The age of multi-core computers is particularly well suited for maximizing the speed of xlsgen scenarios.
In the following is a rather simple piece of code run in multiple threads (the number of threads is evaluated from the actual physical hardware count), that adds pseudo-random content to a spreadsheet. It is written in Java, VB.NET, C# and C++ and is available in the /samples folder of the install.
| Java code |
class multicore_threads {
public static class WorkerThread extends Thread {
protected XlsEngine m_engine;
protected boolean m_bStopped;
protected String m_szFilename;
WorkerThread(XlsEngine engine, String szFilename)
{
m_engine = engine;
m_bStopped = false;
m_szFilename = szFilename;
}
public boolean IsStopped()
{
return m_bStopped;
}
public void run()
{
XlsWorkbook wbk = m_engine.New(m_szFilename);
XlsWorksheet wksht = wbk.AddWorksheet( "sheet1" );
int cnt = 0;
for (int r = 1; r < 40000; r++)
{
for (int c = 1; c <= 20; c++)
{
wksht.putLabel(r, c * 2 + 0, "Label");
wksht.putNumber(r,c * 2 + 1, cnt++);
}
}
wbk.Close();
m_bStopped = true;
}
public void destroy()
{
}
}
public static void main(String[] args) {
XlsEngine engine = new XlsEngine("./../../../xlsgen.dll");
int nbThreads = Runtime.getRuntime().availableProcessors();
System.out.println("multicore sample : " + nbThreads + " threads being created (one per core)");
long startTicks = System.currentTimeMillis();
List arrThreads = new ArrayList(nbThreads);
for (int i = 0; i < nbThreads; i++)
{
WorkerThread t = new WorkerThread(engine, "myfile" + i + ".xls");
t.start();
arrThreads.add(t);
}
while (true)
{
try
{
Thread.sleep(100);
}
catch (InterruptedException e)
{
}
boolean bAtLeastOneRunning = false;
for (int i = 0; i < nbThreads; i++)
{
WorkerThread t = (WorkerThread) arrThreads.get(i);
if (!t.IsStopped())
{
bAtLeastOneRunning = true;
break;
}
}
if (!bAtLeastOneRunning)
break;
}
long endTicks = System.currentTimeMillis();
long secs = (endTicks - startTicks) / 1000;
System.out.println("test duration = " + secs + " seconds");
BufferedReader br = new BufferedReader( new InputStreamReader( System.in ) );
try
{
br.readLine();
}
catch(IOException e)
{
}
}
}
|
| VB.NET code |
Imports System
Imports System.Threading
Imports xlsgen
Module Module1
Public Class WorkerThread
Protected m_engine As CoXlsEngine
Protected m_szFilename As String
Protected m_bStopped As Boolean
Sub New(ByVal engine As CoXlsEngine, ByVal szFilename As String)
m_engine = engine
m_szFilename = szFilename
m_bStopped = False
End Sub
Public Function IsStopped() As Boolean
IsStopped = m_bStopped
End Function
Public Sub Run()
' code begins here
'...
Dim wbk As IXlsWorkbook
wbk = m_engine.New(m_szFilename)
Dim wksht As IXlsWorksheet
wksht = wbk.AddWorksheet("sheet1")
Dim cnt = 0
For r = 1 To 40000
For c = 1 To 20
wksht.Label(r, c * 2 + 0) = "Label"
wksht.Number(r, c * 2 + 1) = cnt
cnt = cnt + 1
Next
Next
wbk.Close()
m_bStopped = True
End Sub
End Class
Public Class Program
Public Shared Sub Main()
Dim startTicks = DateTime.Now.Ticks
Dim engine As CoXlsEngine = New CoXlsEngine
Dim arrThreads As New List(Of WorkerThread)
Dim nbThreads = System.Environment.ProcessorCount
Console.WriteLine("multicore sample : " & nbThreads & " threads being created (one per core)")
' create worker threads
'
For i = 1 To nbThreads
Dim t As New WorkerThread(engine, "myfile" & i & ".xls")
arrThreads.Add(t)
ThreadPool.QueueUserWorkItem( _
New WaitCallback(AddressOf ThreadProc), t
)
Next
Console.WriteLine("Worker threads started.")
' wait for all worker threads to end
'
While (True)
Thread.Sleep(100)
Dim bAtLeastOneRunning = False
For Each t As WorkerThread In arrThreads
If (t.IsStopped() = False) Then
bAtLeastOneRunning = True
Exit For
End If
Next
If (bAtLeastOneRunning = False) Then
Exit While
End If
End While
Dim endTicks = DateTime.Now.Ticks
Dim elapsedSpan As TimeSpan = New TimeSpan(endTicks - startTicks)
Console.WriteLine("test duration = " & elapsedSpan.TotalSeconds & " seconds.")
Console.WriteLine("Main thread exits.")
Console.ReadLine()
End Sub
' This thread procedure performs the task.
Shared Sub ThreadProc(ByVal stateInfo As Object)
Dim t As WorkerThread
t = stateInfo
t.Run()
End Sub
End Class
|
| C# code |
class WorkerThread
{
protected CoXlsEngine m_engine;
protected String m_szFilename;
protected bool m_bStopped;
public WorkerThread(CoXlsEngine engine, String szFilename)
{
m_engine = engine;
m_szFilename = szFilename;
m_bStopped = false;
}
public bool IsStopped()
{
return m_bStopped;
}
public void Run()
{
// code begins here
//...
IXlsWorkbook wbk = m_engine.New(m_szFilename);
IXlsWorksheet wksht = wbk.AddWorksheet( "sheet1" );
int cnt = 0;
for (int r = 1; r < 40000; r++)
{
for (int c = 1; c <= 20; c++)
{
wksht.set_Label(r, c * 2 + 0, "Label");
wksht.set_Number(r, c * 2 + 1, cnt++);
}
}
wbk.Close();
m_bStopped = true;
}
}
class Program
{
static void Main(string[] args)
{
long startTicks = DateTime.Now.Ticks;
CoXlsEngine engine = new CoXlsEngine();
List<WorkerThread> arrThreads = new List<WorkerThread>();
int nbThreads = System.Environment.ProcessorCount;
Console.WriteLine("multicore sample : " + nbThreads + " threads being created (one per core)");
// create worker threads
//
for (int i = 0; i < nbThreads; i++)
{
WorkerThread t = new WorkerThread(engine, "myfile" + i + ".xls");
arrThreads.Add(t);
ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadProc), t);
}
Console.WriteLine("Worker threads started.");
// wait for all worker threads to end
//
while (true)
{
Thread.Sleep(100);
bool bAtLeastOneRunning = false;
for (int i = 0; i < nbThreads; i++)
{
WorkerThread t = arrThreads.ElementAt(i);
if (!t.IsStopped())
{
bAtLeastOneRunning = true;
break;
}
}
if (!bAtLeastOneRunning)
break;
}
long endTicks = DateTime.Now.Ticks;
TimeSpan elapsedSpan = new TimeSpan(endTicks - startTicks);
Console.WriteLine("test duration = " + elapsedSpan.TotalSeconds + " seconds.");
Console.WriteLine("Main thread exits.");
Console.ReadLine();
}
// This thread procedure performs the task.
static void ThreadProc(Object stateInfo)
{
WorkerThread t = (WorkerThread)stateInfo;
t.Run();
}
}
|
| C/C++ code |
::CoInitialize(NULL);
SYSTEM_INFO sysinfo;
::GetSystemInfo( &sysinfo );
int nbThreads = sysinfo.dwNumberOfProcessors;
TCHAR sztmp[128];
_stprintf(sztmp,"multicore sample : %d threads being created (one per core)\r\n", nbThreads);
OutputDebugString(sztmp);
LPUNITHREAD* coll = new LPUNITHREAD[nbThreads];
DWORD dwStart, dwEnd;
{
xlsgen::IXlsEnginePtr engine( __uuidof(xlsgen::CoXlsEngine) );
dwStart = ::GetTickCount();
int i;
for (i = 0; i < nbThreads; i++)
{
TCHAR szFilename[MAX_PATH];
sprintf(szFilename, "%s%d%s", "myfile", i, ".xls");
CUnitThread* u = new CUnitThread();
if (u)
{
u->Start(engine, i, szFilename);
coll[i] = u;
}
}
while (1)
{
::Sleep(100);
bool bAtLeastOneRunning = false;
for (i = 0; i < nbThreads; i++)
{
if (!coll[i]->IsStopped())
{
bAtLeastOneRunning = true;
break;
}
}
if (!bAtLeastOneRunning)
break;
}
dwEnd = ::GetTickCount();
for (i = 0; i < nbThreads; i++)
{
delete coll[i];
}
delete [] coll;
}
DWORD dwElapsed = dwEnd - dwStart;
DWORD secs = dwElapsed / 1000;
_stprintf(sztmp,"test duration = %d seconds\r\n", secs);
OutputDebugString(sztmp);
::CoUninitialize();
return 0;
--- unitthread.h ---
#pragma once
class CUnitThread;
typedef CUnitThread* LPUNITHREAD;
class CUnitThread
{
// Members
//
protected:
int m_nCnt;
TCHAR m_szFilename[MAX_PATH];
xlsgen::IXlsEnginePtr m_engine;
// thread mgt members
DWORD m_ThreadId ; // ID of thread
HANDLE m_hThread ; // Handle to thread
HANDLE m_hEvent; // Handle to event
HANDLE m_hComponentReadyEvent ; // Event signals thread to continue.
bool m_bStopped;
// Constructor
//
public:
CUnitThread();
virtual ~CUnitThread();
// Methods
//
public :
BOOL Start(xlsgen::IXlsEnginePtr &engine, int id, LPSTR filename);
void Stop();
void Increase();
// Accessors
//
public:
int GetCnt();
bool IsStopped();
// Internal
//
protected:
BOOL StartThread(HANDLE hEvent) ; // Create and start the thread.
BOOL IsThreadStarted() ; // Current thread status
static DWORD WINAPI RealThreadProc(void* pv) ; // Thread procedure
DWORD ClassThreadProc() ; // Member thread procedure
BOOL WaitWithMessageLoop(HANDLE hEvent) ; // Wait for an event, but process window messages.
};
--- unitthread.cpp ---
#include "unitthread.h"
CUnitThread::CUnitThread()
{
m_ThreadId = 0 ;
m_hThread = NULL ;
m_hComponentReadyEvent = m_hEvent = NULL ;
m_bStopped = false;
m_nCnt = 0;
}
CUnitThread::~CUnitThread()
{
if (m_hThread) ::TerminateThread(m_hThread,0);
}
BOOL CUnitThread::Start(xlsgen::IXlsEnginePtr &engine, int id, LPSTR filename)
{
_tcscpy(m_szFilename, filename);
m_nCnt = id;
m_engine = engine;
return StartThread(NULL);
}
void CUnitThread::Stop()
{
}
int CUnitThread::GetCnt()
{
return m_nCnt;
}
void CUnitThread::Increase()
{
m_nCnt++;
}
bool CUnitThread::IsStopped()
{
return m_bStopped;
}
///////////////////////////////////////////////////////////
//
// StartThread
// - Create and start the thread.
//
BOOL CUnitThread::StartThread(HANDLE hEvent)
{
if (IsThreadStarted())
{
if (m_hThread) ::TerminateThread(m_hThread,0);
m_hThread = NULL;
}
// Create the thread.
m_hThread = ::CreateThread(NULL, // Default security
0, // Default stack size
RealThreadProc,
(void*)this,
CREATE_SUSPENDED, // Create the thread suspended.
&m_ThreadId) ; // Get the Thread ID.
if (m_hThread == NULL)
{
DWORD nError = ::GetLastError();
return FALSE ;
}
// Create an event for the thread to signal when it is finished.
m_hComponentReadyEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL) ;
if (m_hComponentReadyEvent == NULL)
{
return FALSE ;
}
// store event handle passed by parent
//
m_hEvent=hEvent;
// Thread was created suspended; start the thread.
DWORD r = ResumeThread(m_hThread) ;
// Wait for the thread to start up before we continue.
WaitWithMessageLoop(m_hComponentReadyEvent) ;
return TRUE;
}
///////////////////////////////////////////////////////////
//
// Current thread status
//
BOOL CUnitThread::IsThreadStarted()
{
return (m_hThread != NULL) ;
}
///////////////////////////////////////////////////////////
//
// Thread procedure
//
DWORD WINAPI CUnitThread::RealThreadProc(void* pv)
{
CUnitThread* pApartment = reinterpret_cast<CUnitThread*>(pv) ;
return pApartment->ClassThreadProc() ;
}
void increaseCnt(CUnitThread* t)
{
t->Increase();
}
///////////////////////////////////////////////////////////
//
// Thread procedure
//
DWORD CUnitThread::ClassThreadProc()
{
// Signal that we are starting.
SetEvent(m_hComponentReadyEvent) ;
// code begins here
//...
xlsgen::IXlsWorkbookPtr wbk;
wbk = m_engine->New( _bstr_t(m_szFilename) );
xlsgen::IXlsWorksheetPtr wksht;
wksht = wbk->AddWorksheet( L"sheet1" );
int cnt = 0;
for (int r = 1; r < 40000; r++)
{
for (int c = 1; c <= 20; c++)
{
wksht->Label[r][c * 2 + 0] = L"Label";
wksht->Number[r][c * 2 + 1] = cnt++;
}
}
wbk->Close();
m_bStopped = true;
return 0 ;
}
///////////////////////////////////////////////////////////
//
// BOOL WaitWithMessageLoop(HANDLE hEvent)
//
BOOL CUnitThread::WaitWithMessageLoop(HANDLE hEvent)
{
while (TRUE)
{
// Wait for the event and for messages.
DWORD dwReturn = ::MsgWaitForMultipleObjects(1,
&hEvent,
FALSE,
INFINITE,
QS_ALLINPUT) ;
if (dwReturn == WAIT_OBJECT_0)
{
// Our event happened.
::CloseHandle(hEvent);
return TRUE ;
}
else if (dwReturn == WAIT_OBJECT_0 + 1)
{
// Handle message to keep client alive.
MSG msg ;
while(::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
::TranslateMessage(&msg);
::DispatchMessage(&msg) ;
}
}
else
{
return FALSE ;
}
}
}
|
xlsgen documentation. © ARsT Design all rights reserved.