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