home *** CD-ROM | disk | FTP | other *** search
- /*
- * thread.h
- *
- * Copyright (C) Alberto Vigata - July 2000 - ultraflask@yahoo.com
- *
- * This file is part of FlasKMPEG, a free MPEG to MPEG/AVI converter
- *
- * FlasKMPEG is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * FlasKMPEG is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GNU Make; see the file COPYING. If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
- #if !defined(THREAD_H)
- #define THREAD_H
-
- #include <windows.h>
- #include <list>
-
- using namespace std;
-
- #include "flasktypes.h"
-
- // Critial Section object
- class CCritSec {
-
-
- CCritSec(const CCritSec &refCritSec);
- CCritSec &operator=(const CCritSec &refCritSec);
-
- CRITICAL_SECTION m_CritSec;
-
- public:
- CCritSec() {
- InitializeCriticalSection(&m_CritSec);
- };
-
- ~CCritSec() {
- DeleteCriticalSection(&m_CritSec);
- };
-
- void Lock() {
- EnterCriticalSection(&m_CritSec);
- };
-
- void Unlock() {
- LeaveCriticalSection(&m_CritSec);
- };
- };
-
- typedef CCritSec CFlCritSec;
-
- // Lock a critical section when object is created
- // Unlock when its destructed
- class CAutoLock {
-
- CAutoLock(const CAutoLock &refAutoLock);
- CAutoLock &operator=(const CAutoLock &refAutoLock);
-
- protected:
- CCritSec * m_pLock;
-
- public:
- CAutoLock(CCritSec * plock)
- {
- m_pLock = plock;
- m_pLock->Lock();
- };
-
- ~CAutoLock() {
- m_pLock->Unlock();
- };
- };
-
- typedef CAutoLock CFlAutoLock;
-
- // Thin wrapper for event objects
- class CFlEvent
- {
- public:
- CFlEvent(BOOL fManualReset= FALSE)
- {
- m_hEvent = CreateEvent(NULL, fManualReset, FALSE, NULL);
- };
-
- ~CFlEvent()
- {
- if (m_hEvent) {
- CloseHandle(m_hEvent);
- }
- };
- void Set() {SetEvent(m_hEvent);};
- BOOL Wait(DWORD dwTimeout = INFINITE) {
- return (WaitForSingleObject(m_hEvent, dwTimeout) == WAIT_OBJECT_0);
- };
- void Reset() { ResetEvent(m_hEvent); };
- BOOL Check() { return Wait(0); };
- protected:
- HANDLE m_hEvent;
-
- };
-
-
- #ifndef InterlockedExchangePointer
- #define InterlockedExchangePointer(Target, Value) \
- (PVOID)InterlockedExchange((PLONG)(Target), (LONG)(Value))
- #endif
-
- // FlasKMPEG Thread class
- //
- // Using CFlThread:
- // Derive a class from CFlThread and put the code to
- // be run in the thread in the DWORD ThreadProc() routine.
- //
- // From the outside world you can use SendCommand() method
- // to send commands to the working thread.
- // The working thread at ThreadProc() has to check for commands
- // from time to time using GetCommand() routine
- class CFlThread {
-
- protected:
- HANDLE m_hThread;
-
- // thread will run this function on startup
- // must be supplied by derived class
- virtual DWORD ThreadProc() = 0;
-
- public:
- struct TCommand
- {
- ui32 nCommand;
- ui64 nParam;
- bool bNeedsReply;
- };
-
- CFlThread()
- {
- m_hThread = NULL;
- m_evCommandTrigger.Reset();
- m_evCommandCompleted.Reset();
- m_evFinish.Reset();
-
- m_nCommandResult =0;
- };
- virtual ~CFlThread() {
- Close();
- }
-
-
-
- CFlCritSec m_AccessLock; // locks access by client threads
- CFlCritSec m_WorkerLock; // locks access to shared objects
-
- // when the thread starts, it calls this function. We unwrap the 'this'
- //pointer and call ThreadProc.
- static DWORD WINAPI InitialThreadProc(LPVOID pv)
- {
- CFlThread * pThread = (CFlThread *) pv;
- HRESULT hr = pThread->ThreadProc();
- pThread->SignalExit();
- return hr;
- };
-
- void SetPriority(DWORD dwPriority)
- {
- SetThreadPriority(m_hThread, dwPriority );
- }
-
- // start thread running - error if already running
- BOOL Create()
- {
- DWORD threadid;
-
- CFlAutoLock lock(&m_AccessLock);
-
- if (ThreadExists()) {
- return FALSE;
- }
-
- m_hThread = CreateThread(
- NULL,
- 0,
- CFlThread::InitialThreadProc,
- this,
- 0,
- &threadid);
-
- if (!m_hThread) {
- return FALSE;
- }
- return TRUE;
- }
-
-
- // accessor thread calls this when done with thread (having told thread
- // to exit)
- void Close() {
- HANDLE hThread = (HANDLE)InterlockedExchangePointer(&m_hThread, 0);
- if (hThread) {
- WaitForSingleObject(hThread, INFINITE);
- CloseHandle(hThread);
- }
- };
-
- // ThreadExists
- // Return TRUE if the thread exists. FALSE otherwise
- BOOL ThreadExists(void) const
- {
- if (m_hThread == 0) {
- return FALSE;
- } else {
- return TRUE;
- }
- }
-
-
- // Returns NULL if no command
- bool GetCommand(TCommand *pCommand)
- {
- CFlAutoLock commandLock(&m_csCommand);
-
- if(m_lCommands.size())
- {
- *pCommand = m_lCommands.front();
- m_lCommands.pop_front();
- return true;
- }
- return false;
- }
-
- // Sends a command to the the thread
- // and blocks until the command is executed
- // Can return a parameter
- ui64 SendCommand(ui32 nCommand, ui64 nParam=0)
- {
- {
- CFlAutoLock commandLock(&m_csCommand);
- TCommand sCommand;
-
- sCommand.nCommand = nCommand;
- sCommand.nParam = nParam;
- sCommand.bNeedsReply = true;
-
- // Add command to the list
- m_lCommands.push_back(sCommand);
- // Reset reply event
- m_evCommandCompleted.Reset();
- // Trigger the command and wait for reply
- m_evCommandTrigger.Set();
- }
- m_evCommandCompleted.Wait();
-
- CFlAutoLock lock(&m_csReply);
- return m_nCommandResult;
- }
-
- // Schedules a command to be executed.
- // Don't return anything
- void ScheduleCommand(ui32 nCommand, ui64 nParam=0)
- {
- TCommand sCommand;
- sCommand.nCommand = nCommand;
- sCommand.nParam = nParam;
- sCommand.bNeedsReply = false;
-
- CFlAutoLock commandLock(&m_csCommand);
- // Add comand
- m_lCommands.push_back(sCommand);
- m_evCommandTrigger.Set();
- }
-
- // Signals a command if there are no previous
- // commands sent. Returns true if the command
- // was sent.
- bool SignalCommand(ui32 nCommand, ui64 nParam=0)
- {
- TCommand sCommand;
-
- sCommand.nCommand = nCommand;
- sCommand.nParam = nParam;
- sCommand.bNeedsReply = false;
-
- CFlAutoLock commandLock(&m_csCommand);
- // Signal commands only if there arent
- // messages waiting on the list
- if(!m_lCommands.size())
- {
- m_lCommands.push_back(sCommand);
- m_evCommandTrigger.Set();
- return true;
- }
- return false;
- }
-
- void WaitCommand()
- {
- m_evCommandTrigger.Wait();
- }
-
- void ReplyCommand(TCommand *pCommand, ui64 nReply=0)
- {
- if(pCommand->bNeedsReply)
- {
- CFlAutoLock lock(&m_csReply);
- m_nCommandResult = nReply;
- m_evCommandCompleted.Set();
- }
- }
-
- void SignalExit()
- {
- // Signal exit event
- m_evFinish.Set();
- }
-
- #define THREAD_COMMAND_COUNT 2
- enum Commands{ noCommand=0, exit };
-
- // Calling Exit signals the thread to exit
- // This function returns only when the thread has exited.
- void Exit()
- {
- if( ThreadExists() )
- {
- SendCommand(exit, 0);
- Close();
- }
- }
- protected:
-
-
- CFlCritSec m_csCommand;
- CFlCritSec m_csReply;
-
- CFlEvent m_evCommandTrigger;
- CFlEvent m_evCommandCompleted;
- CFlEvent m_evFinish;
-
- ui64 m_nCommandResult;
- private:
-
- list<TCommand> m_lCommands;
- };
-
-
- #endif
-