|
Why do you want to do such a thing ? I really don't understand why you want to inherit from ClxThread once again.
You know that the functionalities of your class will be inherited even if there is a class (Poll) in between ?
|
|
|
|
|
I want to inherit ClxThread twice because, i need to create two ClxThreads which are just worker threads. One in the Mainloop and one in Poll. It is looking like I should change ClxThread to have the capablities to be object within Mainloop and Poll instead of a inherited object.
<br />
class ClxThread<br />
{<br />
public:<br />
ClxThread();<br />
virtual ~ClxThread();<br />
<br />
typedef unsigned (__stdcall *PTHREADFUNC)(void *);<br />
bool CreateNewThread(void);<br />
bool CreateNewThread(PTHREADFUNC pThreadFunc);<br />
bool Wait();
bool Suspend();
bool Resume();
bool Kill();
bool IsActive();
<br />
virtual void ThreadEntry(){ }<br />
virtual void ThreadExit(){ }<br />
virtual void ThreadRun(){ }<br />
<br />
static UINT WINAPI _ThreadFunc(LPVOID pParam);<br />
<br />
public:<br />
HANDLE m_hThread;
UINT uiThreadId;
<br />
bool m_bActive;
DWORD m_lpId;
};<br />
The main loop classes header.
<br />
<br />
class mainloop : public LENZE_8200_MOTION, private ClxThread<br />
{<br />
public:<br />
mainloop();<br />
~mainloop();<br />
<br />
void Start(void){ CreateNewThread( ); };
<br />
protected: <br />
<br />
void init_mc362X(void);<br />
bool read_mc362x(void);<br />
bool read_lenze_cfg_sheet(void);<br />
bool read_independencer( void );<br />
<br />
private: <br />
void ThreadRun(void); <br />
<br />
MC362X_MOTION isacard;
<br />
ClxUdp cmd_socket;
ClxUdp data_socket;
<br />
bool isRaising;<br />
void Raise(void);<br />
bool Balance_A( double position );<br />
void Balance_B(void);<br />
void init_lift(void);<br />
void lift(void);<br />
<br />
private:<br />
bool m_bBalanced;<br />
char m_cStateCurrent;<br />
char m_cStateLast;<br />
bool m_bDown;<br />
bool m_bEStop;<br />
bool m_bPortUp;<br />
bool m_bStarboard;<br />
bool m_bCanopyOpen;<br />
bool m_bUp;<br />
char m_cCommand; <br />
<br />
};<br />
The Poll classer headers
<br />
class LENZE_8200_MOTION : public ClxThread, protected CLX_LENZE_8200<br />
{<br />
public:<br />
LENZE_8200_MOTION(void);<br />
~LENZE_8200_MOTION(void);<br />
<br />
public:<br />
bool init_lenze8200( int comm_port, int baud_rate, long timeout_ms, int maxtxfailures );<br />
bool start_lenze8200(void){ return CreateNewThread(); }<br />
<br />
void pitch_set_address( char address ){ return SetAddress( &pitch_axis_data, address ); };<br />
char pitch_get_address( void ){ return GetAddress( &pitch_axis_data ); }<br />
<br />
}<br />
Scott Dolan
Jernie Corporation
Engineering & Manufacturing
Software, Hardware, & Enclosures
|
|
|
|
|
My 2 cents...
From the sound of the class names involved -
If you think in terms of "is a..." and "has a..." where "is a..." means you derive from and "has
a..." means you have a member object, it sounds like Poll_LenzeInvertors doesn't need to BE a
thread object but needs to HAVE a thread object.
The same with mainloop - is mainloop a poll object, or does it need to have a poll object.
Maybe something to think about in the design. If not, simply ignore
Mark
"Posting a VB.NET question in the C++ forum will end in tears." Chris Maunder
|
|
|
|
|
Mark,
I think you are right, I am thinking I need stop inheriting a ClxThread and declare a clxthread object within the mainloop and poll_lenze class. However, I have been struggling to pass a void ThreadFunc(void) into CreateNewThread(PTHREADFUNC pThreadFunc); which turns the function ThreadFunc into working thread/function. However, if i create a function in mainloop like this static UINT WINAPI MaintainingThreadProc(LPVOID pParam); and pass it into CreateNewThread(PTHREADFUNC pThreadFunc) Than, MaintainingThreadProc() function becomes a worker thread. I really would like to just pass the stardard void ThreadFunc(void) function prototype if possible.
class ClxThread<br />
{<br />
public:<br />
ClxThread();<br />
virtual ~ClxThread();<br />
<br />
typedef unsigned (__stdcall *PTHREADFUNC)(void *);<br />
bool CreateNewThread(void);<br />
bool CreateNewThread(PTHREADFUNC pThreadFunc);<br />
bool Wait();
bool Suspend();
bool Resume();
bool Kill();
bool IsActive();
<br />
virtual void ThreadEntry(){ }<br />
virtual void ThreadExit(){ }<br />
virtual void ThreadRun(){ }<br />
<br />
static UINT WINAPI _ThreadFunc(LPVOID pParam);<br />
<br />
public:<br />
HANDLE m_hThread;
UINT uiThreadId;
<br />
bool m_bActive;
DWORD m_lpId;
};<br />
Scott Dolan
Jernie Corporation
Engineering & Manufacturing
Software, Hardware, & Enclosures
|
|
|
|
|
ScotDolan wrote: I am thinking I need stop inheriting a ClxThread and declare a clxthread object within the mainloop and poll_lenze class.
Maybe Whatever is best for your design. I suppose since mainloop and poll_lenze both have
associated threads, they could each derive from ClxThread, but mainloop, then, shouldn't be
derived from poll_lenze since mainloop is not a poll_lenze.
ScotDolan wrote: if i create a function in mainloop like this static UINT WINAPI MaintainingThreadProc(LPVOID pParam); and pass it into CreateNewThread(PTHREADFUNC pThreadFunc)
I'm not sure how you've implemented your ClxThread class, but from the header info,
CreateNewThread(PTHREADFUNC pThreadFunc) needs as a parameter a pointer to a function declared as
unsigned __stdcall func(void *). You shouldn't be able to pass a pointer to a function declared
as UINT WINAPI MaintainingThreadProc(LPVOID pParam).
Since you've put a nice little wrapper around a thread, I'm not sure why you need to pass a
thread proc in...
Mark
"Posting a VB.NET question in the C++ forum will end in tears." Chris Maunder
|
|
|
|
|
ScotDolan wrote: However, I have been struggling to pass a void ThreadFunc(void) into CreateNewThread(PTHREADFUNC pThreadFunc); which turns the function ThreadFunc into working thread/function.
Why would you do that. Wouldn't a thread class encapsulate the HANDLE and the Thread function?
led mike
|
|
|
|
|
The purpose of the thread class is to make simple functions that consolidate, hide all the mondain task that need to be performed to start, kill, suspend, resume, a thread. The object is to try to prevent any Operating System specific code from getting into the my mainloop and poll-lenze code. This will make it easier for me to port the code over to Linux, Unix or any other os that supports C++. This is why the i use ThreadEnter(),ThreadRun(), and ThreadExit() can all be override. Because, ThreadEnter(),ThreadRun(), and ThreadExit() get called in the worker thread. other object is to keep the create a spreate function where the thread code goes.
The end results is that when it comes time to port the code over to a new Os, i should only have to rewrite ClxThread.
<br />
#pragma once<br />
<br />
<br />
class ClxThread<br />
{<br />
public:<br />
ClxThread();<br />
virtual ~ClxThread();<br />
<br />
typedef unsigned (__stdcall *PTHREADFUNC)(void *);<br />
bool CreateNewThread(void);<br />
bool CreateNewThread(PTHREADFUNC pThreadFunc);<br />
bool Wait();
bool Suspend();
bool Resume();
bool Kill();
bool IsActive();
<br />
virtual void ThreadEntry(){ }<br />
virtual void ThreadExit(){ }<br />
virtual void ThreadRun(){ }<br />
<br />
static UINT WINAPI _ThreadFunc(LPVOID pParam);<br />
<br />
public:<br />
HANDLE m_hThread;
UINT uiThreadId;
<br />
bool m_bActive;
DWORD m_lpId;
};<br />
#include "stdafx.h"<br />
#include ".\ClxThread.h"<br />
#include <process.h><br />
<br />
<br />
ClxThread::ClxThread()<br />
{<br />
m_hThread = NULL; <br />
m_bActive = false;<br />
uiThreadId = NULL;<br />
}<br />
<br />
<br />
ClxThread::~ClxThread()<br />
{<br />
Kill();<br />
}<br />
<br />
bool ClxThread::CreateNewThread(PTHREADFUNC pThreadFunc)<br />
{<br />
if( m_hThread == NULL )<br />
{<br />
<br />
<br />
<br />
m_hThread = (HANDLE)_beginthreadex(NULL, 0, pThreadFunc, this, CREATE_SUSPENDED, &uiThreadId);
<br />
if ( NULL != m_hThread)<br />
{<br />
ResumeThread( m_hThread );<br />
m_bActive = true;<br />
return true;<br />
}else{<br />
m_bActive = false;<br />
<br />
}<br />
}<br />
<br />
return true;<br />
}<br />
<br />
bool ClxThread::CreateNewThread(void)<br />
{<br />
if( m_hThread == NULL )<br />
{<br />
<br />
<br />
<br />
m_hThread = (HANDLE)_beginthreadex(NULL, 0, _ThreadFunc, this, CREATE_SUSPENDED, &uiThreadId);
<br />
if ( NULL != m_hThread)<br />
{<br />
ResumeThread( m_hThread );<br />
m_bActive = true;<br />
return true;<br />
}else{<br />
m_bActive = false;<br />
<br />
}<br />
}<br />
<br />
return true;<br />
}<br />
<br />
<br />
bool ClxThread::Suspend(void)<br />
{<br />
m_bActive = false;<br />
return (-1 != SuspendThread(m_hThread));
}<br />
<br />
<br />
<br />
bool ClxThread::Kill(void)<br />
{<br />
if( TerminateThread(m_hThread, 1) )
{<br />
m_hThread = NULL;<br />
m_bActive = false;<br />
return 1;<br />
}else{<br />
return 0;<br />
}<br />
}<br />
<br />
<br />
<br />
bool ClxThread::Resume(void)<br />
{<br />
m_bActive = true;<br />
return (-1 != ResumeThread(m_hThread));
}<br />
<br />
<br />
<br />
bool ClxThread::Wait(void)<br />
{<br />
return (WAIT_OBJECT_0 == WaitForSingleObject(m_hThread, INFINITE));<br />
}<br />
<br />
<br />
<br />
bool ClxThread::IsActive(void)<br />
{<br />
return m_bActive;<br />
}<br />
<br />
<br />
<br />
<br />
<br />
UINT WINAPI ClxThread::_ThreadFunc(LPVOID pParam)<br />
{<br />
ClxThread* pThis = reinterpret_cast<ClxThread*>( pParam );<br />
_ASSERTE( pThis != NULL );<br />
<br />
pThis->ThreadEntry();
pThis->ThreadRun();<br />
pThis->ThreadExit();
<br />
pThis->m_bActive = false;<br />
pThis->m_hThread = NULL;<br />
pThis->m_lpId = NULL;<br />
<br />
return 1L;<br />
}
Scott Dolan
Jernie Corporation
Engineering & Manufacturing
Software, Hardware, & Enclosures
|
|
|
|
|
But again, why do you need a member function that takes a function pointer as an argument if
you've encapsulated the threadproc so nicely? Your virtual functions expose derived classes to
the threadproc generically.
Mark
"Posting a VB.NET question in the C++ forum will end in tears." Chris Maunder
|
|
|
|
|
I don't know why you have:
bool CreateNewThread(PTHREADFUNC pThreadFunc);<br />
virtual void ThreadEntry(){ }<br />
virtual void ThreadExit(){ }
It would seem the virtual ThreadRun() would be a complete implementation alone.
led mike
|
|
|
|
|
The purpose of bool CreateNewThread(PTHREADFUNC pThreadFunc); is so ClxThread can be used without having to be inherited. So, i can declare a ClxThread object inside of mainloop instead of inheriting clxthread. Then, i pass in the member function of mainloop into ClxThread define object and it will run in a different thread. This way, i can uses ClxThread as a inherited object or static object.
This would prevent the dreaded diamond effect.
Scott Dolan
Jernie Corporation
Engineering & Manufacturing
Software, Hardware, & Enclosures
|
|
|
|
|
That makes no sense at all. In that scenario the class has no control over the thread function and therefore the concept of encapsulation does not exist.
ScotDolan wrote: The purpose of bool CreateNewThread(PTHREADFUNC pThreadFunc); is so ClxThread can be used without having to be inherited. So, i can declare a ClxThread object inside of mainloop instead of inheriting clxthread.
For that scenario why wouldn't you declare an inherited class "inside of mainloop"?
led mike
|
|
|
|
|
For that scenario why wouldn't you declare an inherited class "inside of mainloop"?
Mike,
That is exactly what I am trying to do. However, I want mainloop to inherit ClxThread. but i also need it to inherit a Poll_Invertors. The problem is Poll_Invertors also inherits a ClxThread to create its own thread. The results is i end up with only one thread even being started ie basicly dreaded diamond.
mainloop
/ \
/ \
/ \
/ \
ClxThread Poll_Invertors
\
\
\
ClxThread
The mainloop code
<br />
class mainloop : public Poll_Invertors, public ClxThread<br />
{<br />
public:<br />
mainloop();<br />
~mainloop();<br />
void Start(void){ CreateNewThread( ); };
protected: <br />
<br />
void init_mc362X(void);<br />
bool read_mc362x(void);<br />
bool read_lenze_cfg_sheet(void);<br />
bool read_independencer( void );<br />
<br />
private: <br />
void ThreadRun( void );
MC362X_MOTION isacard;
ClxUdp cmd_socket;
ClxUdp data_socket;
}<br />
The Poll_Invertors Header
<br />
lass LENZE_8200_MOTION : public ClxThread, protected CLX_LENZE_8200<br />
{<br />
public:<br />
LENZE_8200_MOTION(void);<br />
~LENZE_8200_MOTION(void);<br />
<br />
public:<br />
bool init_lenze8200( int comm_port, int baud_rate, long timeout_ms, int maxtxfailures );<br />
bool start_lenze8200(void){ return CreateNewThread(); }<br />
<br />
void pitch_set_address( char address ){ return SetAddress( &pitch_axis_data, address ); }; ...<br />
char pitch_get_address( void ){ return GetAddress( &pitch_axis_data ); }; <br />
<br />
private: <br />
void ThreadRun(void);
void RunAll( void ); <br />
<br />
LNZ82_INVRT_DATA pitch_axis_data;<br />
LNZ82_INVRT_DATA roll_axis_data;<br />
LNZ82_INVRT_DATA lift_axis_data;<br />
LNZ82_INVRT_DATA counterweight_axis_data;<br />
ClxSafeQue<char> m_sqInvertorsCmdQue;<br />
char m_iInvertorsPollState;<br />
<br />
char pitch_init(LNZ82_INVRT_DATA *axis);<br />
char roll_init(LNZ82_INVRT_DATA *axis); <br />
char lift_init(LNZ82_INVRT_DATA *axis);<br />
char counterweight_init(LNZ82_INVRT_DATA *axis);<br />
<br />
<br />
<br />
void SetAddress( LNZ82_INVRT_DATA *axis, char address ); <br />
char GetAddress( LNZ82_INVRT_DATA *axis ); <br />
void SetOperatingVoltage( LNZ82_INVRT_DATA *axis, int volts ); <br />
char GetOperatingVoltage( LNZ82_INVRT_DATA *axis); <br />
bool GetOutputVoltage( LNZ82_INVRT_DATA *axis, double *dTemp); <br />
bool GetOutputCurrent( LNZ82_INVRT_DATA *axis, double *dTemp); <br />
bool GetOutputFrequencey( LNZ82_INVRT_DATA *axis, double *dTemp); <br />
bool GetOutputTemperature( LNZ82_INVRT_DATA *axis, double *dTemp); <br />
bool GetBusVoltage( LNZ82_INVRT_DATA *axis, double *dTemp); <br />
bool GetPoweronTime( LNZ82_INVRT_DATA *axis, double *dTemp); <br />
bool GetOperatingTime( LNZ82_INVRT_DATA *axis, double *dTemp); <br />
<br />
};<br />
Scott Dolan
Jernie Corporation
Engineering & Manufacturing
Software, Hardware, & Enclosures
|
|
|
|
|
At this point we are having a communication breakdown. I sugggest you take a fresh look at your design. statements like: "I want mainloop to inherit ClxThread. but i also need it to inherit a Poll_Invertors." indicate that you are experiencing myopia. Step away from that thinking completely and try to see a different approach.
led mike
|
|
|
|
|
ScotDolan wrote: the mainloop class inherits,
ClxThread object, and Poll_LenzeInvertors object. The Poll_LenzesInvertors objects also inherits ClxThread object.
Not a good idea. This is known as the diamond multiple inheritance[^] problem and is usually indicative of a design problem.
led mike
|
|
|
|
|
Is there any Network based API Call to determine whether a machine exists on a network, a bit like what the '_access' call does for files?
|
|
|
|
|
Not sure, but I would guess there is, have you checked the Network API Documentation?
led mike
|
|
|
|
|
Thanks Mike!
Gonna use NetWkstaGetInfo()
|
|
|
|
|
rw104 wrote: Is there any Network based API Call to determine whether a machine exists on a network...
Will IsDestinationReachable() work for you? If not, how about NetServerGetInfo() or NetWkstaGetInfo() ?
"A good athlete is the result of a good and worthy opponent." - David Crow
"To have a respect for ourselves guides our morals; to have deference for others governs our manners." - Laurence Sterne
|
|
|
|
|
Sounds good thanks!!!
|
|
|
|
|
I am trying to write a simple GDI program that displays a countdown timer(MM:SS:hh). I am just using the WM_PAINT message to display the updated time and calling InvalidateRect() in my main loop. This however causes the screen to flash as I am clearing the screen before I redraw the text.
FillRect(hdc, &rPos, (HBRUSH)GetStockObject(BLACK_BRUSH));
DrawText(hdc, stTime, stTime.GetLength(), &rPos, DT_CENTER | DT_WORDBREAK); Any suggestions on how I can stop the text from flashing while still being able to update at hundreths of a second?
Thanks, Dustin
|
|
|
|
|
InvalidateRect with the last [bErase] parameter FALSE. This will prevent from flickering.
If you will have a problem with the messed drawings (caused by previous drawings) you could use non-transparent mode or somth else like drawing a new background before the actual text is drawn [which I could see is done by your FillRect call].
--
=====
Arman
|
|
|
|
|
I had actually been using InvalidatRect with bErase set to false. The problem was that I was using transparent mode as you stated, and not seting the background of the text like Mark suggested.
Thanks for the help, Dustin
|
|
|
|
|
Now you are doing right.
The problem was that I was using transparent mode as you stated
Well, I said use 'non-transparent'
--
=====
Arman
|
|
|
|
|
Instead of drawing the background and drawing the text in two steps, try doing it in one:
::SetTextColor(hdc, RGB(0xFF,0xFF,0xFF));
::SetBkColor(hdc, RGB(0x00,0x00,0x00));
::DrawText(hdc, stTime, stTime.GetLength(), &rPos, DT_CENTER | DT_WORDBREAK);
You'll also want to follow Arman's advice so the background doesn't get repainted every update.
Also, WM_PAINT isn't the only place you can draw on the window from. You can draw the text from
anywhere you want. WM_PAINT messages are low priority so if you need better performance do
the DrawText from elsewhere. If it's from a different thread, you need to sync acess to the
HDC as always.
*edit* (Thanks Michael Dunn)
You'll still need to redraw the window contents in response to WM_PAINT and/or
WM_ERASEBKGND so the window is refreshed when it needs updating (e.g when another window is
dragged across it and/or off it).
*end edit*
Mark
-- modified at 14:21 Monday 14th May, 2007
"Posting a VB.NET question in the C++ forum will end in tears." Chris Maunder
|
|
|
|
|
Thanks for the halp Mark, that worked perfectly. I've become so dependent on DirectX I've forgotten how to use GDI properly.
Dustin
|
|
|
|
|