win7: Wie in C "Keine Rückmeldung" verhindern?

29/05/2015 - 16:46 von ha | Report spam
Hallo. Das Problem betrifft ein C-Programm.

Wirklich fündig wurde ich nicht zu dem Thema.
Allgemein wird empfohlen, Routinen die etwas lànger
brauchen in einen eigenen Thread auszulagern.

Geht es nicht einfacher? Zumal ich im Programmfenster
eine Fortschrittsanzeige (Hochzàhlen in einem Statusfeld)
unterbringen will. Und ich las u.a., das ein Thread nicht
ohne weiteres in ein Fenster schreiben kann.

Bevor ich in falscher Richtung experimentiere, frage ich
erstmal hier, ob jemand eine einfache Idee hat.


Gibt es nicht eine Funktion, die ich in dem Schleifenkonstrukt
regelmàßig aufrufen kann, um mich in Intervallen beim Betriebssystem
zu "melden" ?
 

Lesen sie die antworten

#1 Volker Bartheld
29/05/2015 - 20:58 | Warnen spam
Hallo!

On Fri, 29 May 2015 16:46:57 +0200, ha wrote:
Hallo. 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.

Geht 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.

Und 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/li...p/bb760816(v=vs.85).aspx
http://www.functionx.com/win32/cont...ssBars.htm

Gibt 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/...-intensive
https://msdn.microsoft.com/en-us/li...ating_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úLSE, BOOL bInitialStateúLSE );
~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úLSE);
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

Ähnliche fragen