// Copyright © 1998 by Jon Shemitz, all rights reserved.
// Permission is hereby granted to freely use, modify, and
// distribute this source code PROVIDED that all six lines of
// this copyright and contact notice are included without any
// changes. Questions? Comments? Offers of work?
// mailto:jon@midnightbeach.com - http://www.midnightbeach.com
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "SynchedThreads.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
// Simple threads
TSimpleThread::TSimpleThread( TThreadFunction _Action,
void* _Data, bool RunNow)
: TThread(true), // initialize suspended
ThreadFunction(_Action), Data(_Data)
{
FreeOnTerminate = true;
if (RunNow) Resume();
} // TSimpleThread::TSimpleThread
void TSimpleThread::AbortThread()
{
Suspend(); // Can't kill a running thread
Free(); // Kills thread
} // TSimpleThread::AbortThread
// Wait threads (basic synchronization)
void MsgWaitForSingleObject(HANDLE Handle)
{
while (true)
if (MsgWaitForMultipleObjects( 1, & Handle, False,
INFINITE, QS_ALLINPUT )
== WAIT_OBJECT_0 + 1) Application->ProcessMessages();
else break;
} // MsgWaitForSingleObject
TProcessInformation SpawnProcess(char* Command)
{
TStartupInfo StartupInfo;
TProcessInformation Result;
memset(& StartupInfo, 0, sizeof(TStartupInfo));
StartupInfo.cb = sizeof(TStartupInfo);
CreateProcess( NULL, Command, NULL, NULL, false, 0, NULL, NULL,
& StartupInfo, & Result );
return Result;
} // SpawnProcess
TWaitThread::TWaitThread( TThreadFunction _Action, void* _Data )
: TSimpleThread(_Action, _Data, false),
AbortFlag(NULL) { };
void TWaitThread::AbortThread()
{
assert(AbortFlag != NULL);
*AbortFlag = true;
inherited::AbortThread();
} // TWaitThread::AbortThread
void TWaitThread::Run(bool MsgWait) throw (EAbort*)
{
bool Aborted = false;
AbortFlag = & Aborted;
Resume();
if (MsgWait) MsgWaitForSingleObject((HANDLE) Handle);
else inherited::WaitFor();
if (Aborted) Abort;
} // TWaitThread::Run
void MsgWaitForThread( TWaitThread*& Thread,
TThreadFunction Handler, void* Data)
throw (EAbort*)
{
Thread = new TWaitThread(Handler, Data);
Thread->MsgWaitFor();
Thread = NULL;
} // TWaitThread::TWaitThread
// Stop/start threads
EAbortedThread::EAbortedThread()
: std::runtime_error("Aborted thread") {};
EThreadInUse::EThreadInUse()
: std::logic_error("Thread in use") {};
TStopStartThread::TStopStartThread()
: TSimpleThread((TThreadFunction) NULL, NULL, false)
{
Event = CreateEvent(NULL, true, false, NULL);
// API call is smaller and simpler than VCL wrapper
assert(Event != NULL);
Waiting = Aborted = false;
} // TStopStartThread::TStopStartThread
void TStopStartThread::Run( TThreadFunction _Action, void* _Data,
bool MsgWait )
throw (EAbort*, EAbortedThread, EThreadInUse)
{
if (Waiting) throw EThreadInUse();
if (Aborted) throw EAbortedThread();
Waiting = true;
ThreadFunction = _Action;
Data = _Data;
ResetEvent(Event);
Resume();
if (MsgWait) MsgWaitForSingleObject(Event);
else WaitForSingleObject(Event, INFINITE);
Waiting = false;
if (Aborted) Abort(); // throw EAbort();
} // TStopStartThread::Run
void __fastcall TStopStartThread::Execute()
{
while (!Terminated) {
assert(ThreadFunction != NULL);
ThreadFunction(Data);
SetEvent(Event);
Suspend();
}
} // TStopStartThread::Execute
void TStopStartThread::AbortThread()
{
Suspend(); // deleting a running thread leaves process alive
Aborted = true;
SetEvent(Event);
} // TStopStartThread::AbortThread