Hallo!
Post by haHallo. Das Problem betrifft ein C-Programm.
Allgemein wird empfohlen, Routinen die etwas länger
brauchen in einen eigenen Thread auszulagern.
Jup. Schwer ist das nicht.
Insbesondere, wenn man sich eine vergleichsweise triviale Helperklasse
(schon klar, C++, kein nacktes C) wie CThread hinlegt. S. unten. Von der
erbst Du, implementierst nach Belieben Run(), OnThreadStart(),
OnThreadFinish() und vielleicht OnThreadMessage(), falls Du Deinen
Workerthread kommandieren mußt.
Den Rest übernimmt die Basisklasse. Im Grunde also nur ein Copy&Paste
Deiner länglichen C-Routinen in die Workerthreadfunktionen. Beim Erzeugen
der Klasseninstanz läuft der Thread los (außer, Du willst es anders) und
sobald die Instanz zerstört wird, terminiert auch der Thread. Wartezeit
einstellbar.
Post by haGeht es nicht einfacher? Zumal ich im Programmfenster
eine Fortschrittsanzeige (Hochzählen in einem Statusfeld)
unterbringen will.
Ein Grund mehr für den Workerthread: Den GUI-Thread nicht blockieren.
Post by haUnd ich las u.a., das ein Thread nicht ohne weiteres in ein Fenster schreiben kann.
"In ein Fenster schreiben"? Hmmm. Muß er auch nicht. Der Workerthread hat
üblicherweise einen Handle auf den Mainthread, kann also Send/PostMessage()
dorthin machen. Das reicht, um im Mainthread Handler aufzurufen oder gar
direkt irgendwelche Controls zu verändern. Denn im Grunde wird die
Fortschrittsanzeige auch nur durch Messages gesteuert:
https://msdn.microsoft.com/en-us/library/windows/desktop/bb760816(v=vs.85).aspx
http://www.functionx.com/win32/controls/ProgressBars.htm
Post by haGibt es nicht eine Funktion, die ich in dem Schleifenkonstrukt
regelmäßig aufrufen kann, um mich in Intervallen beim Betriebssystem
zu "melden" ?
Wenn es unbedingt sein muß, dann kannst Du den Messagedispatcher auch
manuell antreiben:
http://stackoverflow.com/questions/5808151/mfc-win32-c-how-to-dispatch-messages-while-doing-a-computationally-intensive
https://msdn.microsoft.com/en-us/library/windows/desktop/ms644928%28v=vs.85%29.aspx#creating_loop
HTH & Gruß,
Volker
<syncobj.h>
#ifndef _SYNC_OBJ_
#define _SYNC_OBJ_
#include <Windows.h>
#include <process.h>
namespace syncobj
{
/////////////////////////////////////////////////////////////////////////////////////////
// CMutex
class CMutex
{
private:
CRITICAL_SECTION _crit_section;
public:
CMutex();
~CMutex();
void Seize();
void Release();
};
class CLock
{
private:
CMutex& _mutex;
public:
CLock( CMutex& mutex_ );
~CLock();
};
/////////////////////////////////////////////////////////////////////////////////////////
// CInterlockedLong
class CInterlockedLong
{
private:
LONG value;
public:
CInterlockedLong( LONG _value );
// under Windows 95 only sign of the returning value is correct
LONG Increment();
LONG Decrement();
};
/////////////////////////////////////////////////////////////////////////////////////////
// CEvent
class CEvent
{
private:
HANDLE _handle;
public:
CEvent( BOOL bManualReset=FALSE, BOOL bInitialState=FALSE );
~CEvent();
operator HANDLE() { return _handle; }
void Signal();
void Reset();
BOOL Wait( DWORD dwMilliseconds=INFINITE ) const;
BOOL IsSignaled() const;
};
/////////////////////////////////////////////////////////////////////////////////////////
// CThread
class CThread // generic worker thread class
{
public:
HANDLE m_threadHandle;
UINT m_threadID;
CThread();
~CThread();
void StartThread();
BOOL StopThread(BOOL bSendQuitMessage=TRUE, BOOL bKillNotResponce=FALSE);
BOOL IsThreadRunning() { return m_threadHandle != NULL; }
BOOL Wait(DWORD dwMilliseconds=INFINITE) { return m_eventStopped.Wait(dwMilliseconds); }
void SetPriority(int nPriority);
BOOL PostMessage(UINT Msg, WPARAM wParam, LPARAM lParam);
protected:
virtual void Run();
virtual void OnThreadMessage(MSG* pMsg) {}
virtual void OnThreadStart() {}
virtual void OnThreadFinish() {}
private:
static UINT __stdcall ThreadFunction(void* pParam);
CEvent m_eventInit, m_eventStopped;
};
} // namespace syncobj
#endif // _SYNC_OBJ_
</syncobj.h>
<syncobj.cpp>
#include <assert.h>
#include "syncobj.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
namespace syncobj
{
/////////////////////////////////////////////////////////////////////////////////////////
// class CMutex
CMutex::CMutex() { InitializeCriticalSection( &_crit_section ); }
CMutex::~CMutex() { DeleteCriticalSection( &_crit_section ); }
void CMutex::Seize() { EnterCriticalSection( &_crit_section ); }
void CMutex::Release() { LeaveCriticalSection( &_crit_section ); }
/////////////////////////////////////////////////////////////////////////////////////////
// class CLock
CLock::CLock( CMutex& mutex_ ) : _mutex(mutex_) { _mutex.Seize(); }
CLock::~CLock() { _mutex.Release(); }
/////////////////////////////////////////////////////////////////////////////////////////
// class CInterlockedLong
CInterlockedLong::CInterlockedLong( LONG _value ) : value(_value) {}
LONG CInterlockedLong::Increment() { return ::InterlockedIncrement(&value); }
LONG CInterlockedLong::Decrement() { return ::InterlockedDecrement(&value); }
/////////////////////////////////////////////////////////////////////////////////////////
// class CEvent
CEvent::CEvent(BOOL bManualReset, BOOL bInitialState) { _handle=CreateEvent(0, bManualReset, bInitialState, 0); }
CEvent::~CEvent() { CloseHandle( _handle ); }
void CEvent::Signal() { ::SetEvent( _handle ); }
void CEvent::Reset() { ::ResetEvent( _handle ); }
BOOL CEvent::Wait( DWORD dwMilliseconds ) const { return ::WaitForSingleObject( _handle, dwMilliseconds )==WAIT_OBJECT_0; }
BOOL CEvent::IsSignaled() const
{
if(::WaitForSingleObject( _handle, 0 )==WAIT_OBJECT_0 ) return TRUE;
return FALSE;
}
/////////////////////////////////////////////////////////////////////////////////////////
// class CThread
CThread::CThread() : m_threadHandle(NULL), m_threadID(0) {}
CThread::~CThread() { assert( m_threadHandle==NULL ); }
void CThread::SetPriority( int nPriority ) { ::SetThreadPriority( m_threadHandle, nPriority ); }
void CThread::StartThread()
{
assert(m_threadHandle==NULL);
m_threadHandle=(HANDLE)_beginthreadex(NULL, 0, ThreadFunction, this, 0, &m_threadID); // start a worker thread and pass in a this-pointer which will be reinterpret_cast-ed (see also http://www.mpdvc.de/html.htm#Q18)
m_eventInit.Wait(); // wait until initialization is complete
}
BOOL CThread::StopThread( BOOL bSendQuitMessage, BOOL bKillNotResponce )
{
if(m_threadHandle==NULL) return TRUE;
if(bSendQuitMessage) PostMessage(WM_QUIT, 0, 0);
BOOL bSuccess=m_eventStopped.Wait(5000); // gracefully wait 5s for thread to signal that it has terminated before killing it if necessary
if(!bSuccess && bKillNotResponce ) TerminateThread(m_threadHandle, 0xDEAD); // thread termination not signaled: kill thread if requested
CloseHandle( m_threadHandle );
m_threadHandle=NULL;
m_threadID=0;
return bSuccess;
}
BOOL CThread::PostMessage(UINT Msg, WPARAM wParam, LPARAM lParam) // send a message to worker thread
{
if(m_threadID==0) return FALSE; // thread not active, skip posting the message
return ::PostThreadMessage(m_threadID, Msg, wParam, lParam); // use the Win API function to send a message to the CThread-object
}
void CThread::Run() // worker thread main message loop
{
OnThreadStart(); // execute some starting code in overloaded class if necessary
MSG msg;
while(GetMessage(&msg, NULL, 0, 0)>0) // run message-loop unless WM_QUIT has been received
{
OnThreadMessage(&msg); // process message
}
if(msg.message==WM_QUIT) OnThreadMessage( &msg );
OnThreadFinish(); // do some cleanup stuff in overloaded class if necessary
}
UINT __stdcall CThread::ThreadFunction(void* pParam) // this is the static callback function for _beginthreadex()
{
CThread& self=*reinterpret_cast<CThread*>(pParam); // extract "this" pointer
MSG msg;
PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE); // peek into the message buffer of the current thread for WM_USER messages but don't remove the message from there (to create msg loop)
self.m_eventInit.Signal(); // signal the initialization has completed (blocked function CThread::StartThread() in main thread context will be continued)
self.Run(); // run the thread
self.m_eventStopped.Signal();
return 1;
}
} // namespace syncobj
</syncobj.cpp>
--
@: W E B 2 0 1 5 at B A R T H E L D dot N E T
3W: www.bartheld.net