|
This looks like an example of some really contemporary design techniques (policies) described by Andrei Alexandrescu in his book "Modern C++ Design."
While his ideas look great in theory, I've never been game to try them out because they look like a maintenance nightmare and it would be harder to find developers capable of maintaining such sophisticated code. Don't be fooled - writing (good) templated code is *much* harder than it first might appear (and VC6's support for templates is woeful!)
There's no reason why a simpler solution would not be just as effective e.g. creating your worker classes as you describe but instantiating them and passing them to ExecutionPlan as runtime parameters rather than templated, compile-time parameters.
If you go the template route, I'd be very interested to hear how it went. Write an article about it!
he he he. I like it in the kitchen! - Marc Clifton (on taking the heat when being flamed)
Awasu v0.4a[^]: A free RSS reader with support for Code Project.
|
|
|
|
|
Thanks for the feedback.
Taka Muraoka wrote:
maintaining such sophisticated code
I tend to agree, but not having done it I am just not certain how complex it will be in the end.
Taka Muraoka wrote:
There's no reason why a simpler solution would not be just as effective e.g. creating your worker classes as you describe but instantiating them and passing them to ExecutionPlan as runtime parameters rather than templated, compile-time parameters.
This was my first idea, but even this will be somewhat complicated and will require a funamental understanding of the implementation to be able to use it. The reason I am looking into templates is because I think the complexity may not be much more and would be far more flexible (I think??) with not much more actual coding on my part.
Taka Muraoka wrote:
If you go the template route, I'd be very interested to hear how it went. Write an article about it!
While I need this for an actual real-life problem, I had thought of using it as the basis for a future article. Only time will tell.
Thanks again,
Matt Gullett
|
|
|
|
|
Matt Gullett wrote:
I am just not certain how complex it will be in the end.
Writing templated code is *much* harder than writing bog-standard OO code because you have no idea what your template parameters are. If you know they're only going to be standard data types like an int or a float that's one thing, but when they're classes like what you're proposing, it gets much more tricky. You either require that all classes have a uniform interface, in which case you might as well just have a class hierarchy, or you allow a varying interface.
With a class hierarchy, you have a base class with a bunch of pure virtual functions and derived classes have to implement them, regardless of whether or not they actually use them. The cool things about policies is that Alexandrescu takes advantage of the fact that template code that is never used doesn't get compiled (and therefore cannot cause compile errors). So he passes in classes with varying interfaces and as long as you don't try to use functionality that is not provided by your template parameter classes, your stuff will work just fine.
The book is worth a read but it's really tough! I couldn't read more than a chapter at a time because it just made my head hurt. I still don't understand half of it
he he he. I like it in the kitchen! - Marc Clifton (on taking the heat when being flamed)
Awasu v0.4a[^]: A free RSS reader with support for Code Project.
|
|
|
|
|
Thanks for the additional advice. I actually own this book, but I have never fully read it. I guess I need to get it out and re-read it.
One thing that concerns me in your statement:
Taka Muraoka wrote:
The cool things about policies is that Alexandrescu takes advantage of the fact that template code that is never used doesn't get compiled (and therefore cannot cause compile errors).
As I understand it, this is not really true. If I need to export a fully-qualified template class from a DLL, the compiler will always compile the whole thing. My software applications make heavy use of DLLs and this has already been an issue when working with STL.
Anyway, you have just about convinced me to not bother with the template based solution, but I will keep researching a little. I have a little time before I need to make a decision.
Thanks,
Matt Gullett
|
|
|
|
|
Matt Gullett wrote:
If I need to export a fully-qualified template class from a DLL, the compiler will always compile the whole thing.
I read something a few months back from a compiler vendor (not Microsoft) who had tried to implement something where you could compile a template class into a .LIB that you could distribute *without* having to supply the source. Apparently it was Really Hard to do and they still couldn't get it to work exactly the way you would expect or want.
Templating is a compile-time thing. For example, how do you put this in a DLL so that somebody can use it at *runtime*:
template< typename T><br />
struct Foo<br />
{<br />
void incrementFoo( T& t ) { ++t ; }<br />
} ;
You don't know what T is until you try to compile something using this class so how can you possibly put it in a DLL (without some kind of pre-compiled template information)?
/taka thinks for a minute...
Unless you mean that VC is compiling everything in a templated class regardless of whether it's used or not. That's (yet another) a problem with VC's template handling, then. It's not supposed to do that.
he he he. I like it in the kitchen! - Marc Clifton (on taking the heat when being flamed)
Awasu v0.4a[^]: A free RSS reader with support for Code Project.
|
|
|
|
|
What I am reffering to is not exporting a template class, but a fully qualified template typedef (typedef may not be the correct term.)
For instance, I have a dll that uses a std::list<csomeclass> and needs to have this passed into one of its exported classes for various functions. To make this work you must write a line something like this (pseudocode):
extern template class __declspec(dllexport) std::list<csomeclass>;
|
|
|
|
|
In this case I'd just use virtual functions and inheritence.
Todd Smith
|
|
|
|
|
Thanks for the advice.
That is what I am leaning towards right now. I think the template solution may just be overly complex for the actual requirements at hand.
Thanks,
Matt Gullett
|
|
|
|
|
I've been working on serial IO for a few days now. To creep up on it, I started out non overlapped, and it was a piece of cake. Then I decided to add a thread to handle the reads. My first version used a while(true) loop in the thread, and polled for data in the receive buffer. It worked fine, but I didn't like the fact that it was always looping. Here's where the fun begins... I changed to overlapped IO, and was amazed that my first version worked (I thought). Unfortunately, it only worked when I sent packets that were relatively small, less than 6 bytes. If I send more than 6 bytes, WaitForMultipleObjects won't return after the first read. I'll paste the thread's code at the end of this. A lot of it is commented out to make sure something (incorrect memory management or whatever) wasn't causing the problem.
Here's the result of my debug so far...
If I send data of just a few bytes, everything works as expcted. WaitForMultibleObjects returns whenever data is received, and waits again the next time it is called.
If I send the magic number of 9 bytes...
WaitForMultipleObjects returns execution to the thread.
I read data out of the port with ReadFile.
Loop back to WaitForMultipleObjects, and wait for more.
Now if I send another character, or string of chars, WaitForMultipleObjects does not return! I have another entry point to read the serial port from the main thread, and if I use it, I can read the data. In addition, when I read the data with that other entry point, the WaitForMultipleObjects function returns, but finds no data since the main thread read it (that's expected). From this point on, WaitForMultipleObjects won't return when characters are received by the port.
I tried clearing the threads lasterror before the ReadFile, and then checked the error after the ReadFile command, and get "command exited normally" or words to that effect.
The readfile is opened with 1000 byte buffers for both read and write.
Any help would be greatly appreciated!
Read Thread.................................................................
UINT CSerial::ReadPortThread(LPVOID lpvParam)
{
CSerial *pSerial = (CSerial*)lpvParam;
int bytesin;
pSerial->hReadEvents[0] = CreateEvent(NULL, true, false, NULL);
pSerial->hReadEvents[1] = CreateEvent(NULL, true, true, NULL);
pSerial->OverlappedRead.hEvent=pSerial->hReadEvents[1];
SetCommMask(pSerial->m_hIDComDev,EV_RXCHAR);
DWORD evt;
DWORD dwHandleSignaled;
SetLastError(0);
while (true)
{
if (!WaitCommEvent(pSerial->m_hIDComDev,&evt, &pSerial->OverlappedRead))
{
if (ERROR_IO_PENDING!=GetLastError())
{
TRACE("WaitCommEvent failed, exiting Read Thread\n");
return 0;
}
}
if (!ResetEvent(pSerial->OverlappedRead.hEvent))
{
TRACE("ResetEvent failed, exiting Read Thread\n");
return 0;
}
dwHandleSignaled=WaitForMultipleObjects(2,
pSerial->hReadEvents,
FALSE,
INFINITE);
switch(dwHandleSignaled)
{
case WAIT_OBJECT_0 + 1:
{
if ( (bytesin=pSerial->ReadDataWaiting()) > 0)
{
char buff[500];
DWORD BytesRead;
TRACE("Before ReadFile ");
pSerial->TraceLastError(GetLastError());
SetLastError(0);
ReadFile(pSerial->m_hIDComDev,
buff,bytesin,&BytesRead,
&pSerial->OverlappedRead);
TRACE("After ReadFile ");
pSerial->TraceLastError(GetLastError());
}
break;
}
case WAIT_OBJECT_0:
{
PurgeComm(pSerial->m_hIDComDev,PURGE_RXABORT | PURGE_RXCLEAR);
return 0;
}
}
}
}
|
|
|
|
|
Wow, this is ugly, all the formatting is gone. Is there a better way to put code up here?
Also, double checked the number of characters that works, and as long as I'm reading no more than 8 characters with ReadFile, everything is fine. If I read 9 or more, is when I get into trouble.
|
|
|
|
|
Put the code in a <pre> block, not <code> - <pre> preserves spacing.
--Mike--
Friday's GoogleFight results: Britney Spears 2,190,000 - Erica Weichers 23
1ClickPicGrabber - Grab & organize pictures from your favorite web pages, with 1 click!
My really out-of-date homepage
Sonork-100.19012 Acid_Helm
|
|
|
|
|
First, don't call ResetEvent() after calling WaitCommEvent(). Your resetting the event which may have gotten set between your call to WaitCommEvent() and your call to ResetEvent(). You should do the ReadFile() first, then wait again, and get rid of the WaitForMultipleObjects. Additionally, I wouldn't use a separate event to signal the thread to quit. I'd just add another member variable for that, or even better, just set the thread handle to NULL. Lastly, you need to ensure your timeouts are set correctly. I've added a sample of what it should like at the end. Below is my implementation of your thread (some stuff removed for brevity, some errors not checked, and probably a few typo's, but you'll get the drift).
for (;;)
{
WaitCommEvent(....);
//check if WaitCommEvent succeeded or failed
if (GetLastError() != ERROR_IO_PENDING){
//something went horribly wrong with WaitCommEvent(), so
//clear all errors and try again
DWORD comerrors;
ClearCommError(pSerial->m_hIDComDev,&comerrors,0);
}else{
//IO is pending, wait for it to finish
if (GetOverlappedResult(pSerial->m_hIDComDev,&pSerial->OverlappedRead,&dwBytes,TRUE)){
//event occurred, see if it was an RX CHAR event
if (dwEvent == EV_RXCHAR){
pSerial->HandleIncomingData()
}else{
//event wasn't an RXCHAR... This can happen if someone changed
//the event mask (a common way to signal the thread to quit)
//so check if we were signaled to quit
if (pSerial->m_hRxThread == NULL)
break;
else
//else the event mask got all buggered up, so reset it
SetCommMask(pSerial->m_hIDComDev,EV_RXCHAR);
}//dwEvent == EV_RXCHAR
}else{
//GetOverLappedResult() result failed... handle that here
...
}
//now reset the event handle so we can start all over again
ResetEvent(pSerial->OverlappedRead.hEvent);
}
void CSerial::HandleIncomingData()
{
DWORD chars_read =0;
bool bDone = false;
//loop until there's no data in the rx buffer
while (!done){
ResetEvent(m_osRead.hEvent);
if (!ReadFile(m_hIDComDev,m_pIncomingData+m_dwDataIndex, m_cbDataBuf-
m_dwDataIndex, &chars_read,&OverlappedRead)){
if (GetLastError != ERROR_IO_PENDING){
//read failed, so just exit
done = true;
continue;
}else{
//read pending, wait for it to complete
DWORD dwRes = WaitForSingleObject(m_osRead.hEvent,INFINITE);
switch (dwRes){
case WAIT_OBJECT_0: //read event has completed
//did the read fail?
if (!GetOverlappedResult(m_hPort,&m_osRead,&chars_read,FALSE)){
done = true; //yep, break out
continue;
}else{
//read succeeded, did we read in any chars?
if (chars_read == 0){
//nope, so we timed out
done = true;
continue;
}else{
//read in some chars, so increment the index
m_dwIndex += chars_read;
//resize the data buffer if necessary
if (m_dwIndex >= m_cbDataBuf)
ResizeBuffer();
}
}
break;
default:
//got an error, so we are definitely done
done = true;
break;
}
}
}else{
//ReadFile succeed immediately, handle the chars
if (chars_read > 0)
m_dwIndex += chars_read;
else
done = true;
if (m_dwIndex >= m_cdDataBuf)
ResizeBuffer();
}
}
}
To signal the thread to quit, do the following:
void CSerial::StopRxThread()
{
//save a copy of our handle
HANDLE temp = m_hRxThread;
//signal the thread to quit by setting the handle to NULL
m_hRxThread = NULL;
//change the event mask to none. This will let the thread
//continue if it's waiting for WaitCommEvent() or
//GetOverlappedResult()
SetCommMask(m_hIDComDev,0);
//wait for the thread to exit
WaitForSingleObject(temp,THREAD_STOP_TIMEOUT);
//thread exited, close the handle
CloseHandle(temp);
}
Lastly, the code for setting the port timeouts
void CSerial::SetPortTimeouts()
{
COMMTIMEOUTS to={0};
to.ReadIntervalTimeout = MAXDWORD;
to.ReadTotalTimeoutMultiplier = MAXDWORD;
to.ReadTotalTimeoutConstant = (DWORD)m_lCommTimeout; // in milliseconds
to.WriteTotalTimeoutConstant = (DWORD)m_lCommTimeout; // in milliseconds
if (m_hPort != 0)
::SetCommTimeouts(m_hPort,&to);
}
Hope this helps,
Pat
|
|
|
|
|
Thanks!
Before I saw your reply, I thought there might be a race condition involving ResetEvent. For grins, I commented the ResetEvent code out, and it started working! I was worried because I didn't think WaitCommEvent should have cleared the manual event, and didn't understand why it was working. Your comments have put me at ease somewhat. Although I'm still not sure what mechanism is responsible for clearing the rxchar event before the call to WaitForMultipleObjects
Now I'll take a look at your suggested implementation. Thanks for the time you put into this!
GaryH
|
|
|
|
|
work_to_live wrote:
Although I'm still not sure what mechanism is responsible for clearing the rxchar event before the call to WaitForMultipleObjects
Ahh, I see where the confusion is. First, you never want the event cleared. You want the event in whatever state it is after WaitCommEvent() completes. If it's set, then you want WaitForMultipleObjects() to return immediately so you can beginning reading data, as that means data is available. If it's reset, then you want to wait until data becomes available, which will happen when the RXCHAR event occurs, and that will set the event.
For overlapped IO, WaitCommEvent() will always return immediately, and you need to check the return result to find out what happened. If the return result is TRUE, the function returned because the specified event occured, in which case the event handle will also be set. If the WaitCommEvent() returns FALSE, then you need to call GetLastError() to find out why. If the result is ERROR_IO_PENDING, only then can you wait on the event handle in the overlapped structure. If you look at my example, this will become plain.
What happened in your case where the thread appears hung was that WaitCommEvent() returned FALSE, and therefore the event handle is still reset. You then call ResetEvent(), but during the time, and RXCHAR event occurs and the event handle becomes set. You then reset it and wait on it, but since there is no mechanism to set the event now, the OS just waits forever.
There's also a problem for the case that WaitCommEvent() succeeds immediately. In that case, the event handle is set. You then immediately reset it and wait on it, which causes the same problem.
For your example, the only time it would work is if 1) WaitCommEvent() fails initially due to IO_PENDING, and then 2) the IO does not complete until after your call to ResetEvent().
There are only 2 times you should reset the event handle.
1) Before calling ReadFile()/WriteFile()
2) Before calling WaitCommEvent()
Never reset the event handle before a call to one of the WaitForxxx functions, or before a call to GetOverlappedResult(). If you do, the event can occur before the call to ResetEvent() completes, in which case the event will never become set again (like what happened here).
Hope this clears it up...
Pat
|
|
|
|
|
|
It's finally starting to sink in. I took one more pass through the WaitCommEvent documentation, and caught the one sentence I missed before... "When this happens, the system sets the hEvent member of the OVERLAPPED structure to the not-signaled state before WaitCommEvent returns" I missed that the previous 10 times I read it!
Thanks again.
|
|
|
|
|
|
I created a deskband and when I turn it on, it is checked. Is there a way to prevent it from becoming checked? I have put in the capability to have more than one band, but I can't create new ones because of this problem.
Thanks
|
|
|
|
|
in my program i have a linked list, which is circular and i need to print out the numbers in the list from a given number.
the number i have to print from is the third number (62) in the list (as shown below) to the end then it has to rap back around and print the first two numbers.any suggestions
92 82 62 72 99
it needs to print out
62 72 99 92 82
[code]
void ClosedList::PrintFrom(int item) const
{
NodeType* currPtr = head->backlink;
NodeType* newNodePtr = new NodeType;
newNodePtr->component = item;
newNodePtr->backlink = currPtr;
currPtr = newNodePtr;
newNodePtr = NULL;
if(!IsEmpty())
{
do
{
cout << currPtr->component << " ";
currPtr = currPtr->backlink;
}while (currPtr != head);
cout << currPtr->component << " ";
}
cout <<endl;
}
bool ClosedList::IsEmpty() const
{
return (head == NULL);
}
[/code]
|
|
|
|
|
If the list is circular, you need to remember the address of the starting point and check for that, so you know when you've looped around.
I'd write an iterator class, and then provide a method of using it to loop the list. I'd also make the print stuff an iostream inserter ( I have an article on this on the site ).
Christian
No offense, but I don't really want to encourage the creation of another VB developer. - Larry Antram 22 Oct 2002
C# will attract all comers, where VB is for IT Journalists and managers - Michael P Butler 05-12-2002
Again, you can screw up a C/C++ program just as easily as a VB program. OK, maybe not as easily, but it's certainly doable. - Jamie Nordmeyer - 15-Nov-2002
|
|
|
|
|
You need something like this:
struct List { List * next; void * data;};
// Walk to the nth node of the list.
List* walk_n(List * lst, unsigned n)
{
for(unsigned i=0; i<n; ++i) lst = lst->next;
return lst;
}
// Walk the list calling fn on each node (until
// the list loops back to the beginning)
void listWalk(List * lst, void(*fn)(void* data))
{
List * last = lst;
do
{
fn(lst->data);
lst = lst->next;
} while (last != lst);
}
With these two functions (which I made general since your
application serves best as a composition of general functions)
you can easily provide your required functionality.
void printFromN(List* lst, unsigned n)
{
listWalk(walk_n(lst, n), printFunction);
}
where print function is some function to output the data
in a list node.
Needless to say, this code is untested, as I just typed it,
but, although there might be a few typos, I hope it communicates
the basic idea.
Of course I have assumed no null lists, that is a whole other
subject that depends on exactly how you are defining your list
structure.
HTH
|
|
|
|
|
Hello,
I am creating a splitter window application where one of the windows is a CHTMLView view (in other words, a web browser). I was wondering if it is possible to put a control bar inside this splitter window, so that I can put labels and textboxes on it.
Does anyone know if this is possible? I was looking at Outlook Express, and it seems to have just that: in the splitter window where the email message is displayed, there is some sort of controlbar where the addressees and subject are displayed.
Does anyone know how to do this?
Thanks,
Trimtrom
|
|
|
|
|
some time mouse shows busy sign(or it is busy).
can any body tell how i may check that mouse is busy or not?
r00d0034@yahoo.com
|
|
|
|
|
errrrr if its eating cheese i guess its busy
otherwise it isnt
(ps: mice dont get busy the computer does)
"traffic lights are for people who can't make their own decisions" biz stuff about me
|
|
|
|
|
*grin* Yes, Imran does ask the same questions over and over again and gives the impression that he has no idea how to search for things himself. In this case, I had just finished explaining that you could poll the mouse position twice and see if it changes before I realised what he meant. Seeing as the busy cursor is just another cursor you set the mouse to, I am not sure there is a way to tell that this is the cursor being used, but I'm not sure.
Christian
No offense, but I don't really want to encourage the creation of another VB developer. - Larry Antram 22 Oct 2002
C# will attract all comers, where VB is for IT Journalists and managers - Michael P Butler 05-12-2002
Again, you can screw up a C/C++ program just as easily as a VB program. OK, maybe not as easily, but it's certainly doable. - Jamie Nordmeyer - 15-Nov-2002
|
|
|
|
|