|
Even
Tata tata;
would generate a compiler error...
If the Lord God Almighty had consulted me before embarking upon the Creation, I would have recommended something simpler.
-- Alfonso the Wise, 13th Century King of Castile.
This is going on my arrogant assumptions. You may have a superb reason why I'm completely wrong.
-- Iain Clarke
[My articles]
|
|
|
|
|
CPallini wrote: would generate a compiler error...
No, that does not generate a compiler error.
But maybe you're laughing at something else ?
Watched code never compiles.
|
|
|
|
|
Did you try it?
In your code the function implementation is missing.
If the Lord God Almighty had consulted me before embarking upon the Creation, I would have recommended something simpler.
-- Alfonso the Wise, 13th Century King of Castile.
This is going on my arrogant assumptions. You may have a superb reason why I'm completely wrong.
-- Iain Clarke
[My articles]
|
|
|
|
|
I think he meant that it won‘t be a compiler problem, but rather something the linker will stumble upon.
|
|
|
|
|
Good point. However I don't know if it is what he meant.
If the Lord God Almighty had consulted me before embarking upon the Creation, I would have recommended something simpler.
-- Alfonso the Wise, 13th Century King of Castile.
This is going on my arrogant assumptions. You may have a superb reason why I'm completely wrong.
-- Iain Clarke
[My articles]
|
|
|
|
|
Your guess is as good a mine, I suppose. Only one person knows for sure.
|
|
|
|
|
It is never referenced, so the linker will not report it.
yeah, good catch!
Watched code never compiles.
|
|
|
|
|
But Onion* pOnion = new Tata is OK, and this is what the code was actually doing when I looked a bit deeper.
Doesnt explain VS though not debugging into the funcs.
==============================
Nothing to say.
|
|
|
|
|
Have you still not solved that issue? VS should step into virtual funcs - I do it every day, using VS 2003, and now that I switched it to VS2010 it works just as well.
Apart from your debugging a remote program - I haven't done that myself, the only thing I can think of is that your code does something different than you think it should. but without seeing the code we can't say. Can you extract the relavnt bits of your code (i. e. the declaration of the virtual func in the base class and how you overrode it in your derived class) and post it?
|
|
|
|
|
Havent got time to spend on the VS issue so it looks like I will never know.
==============================
Nothing to say.
|
|
|
|
|
sir/mam
can you please tell me if there is any particular reason why the following operators can't be oveloaded..
.
::
?:
|
|
|
|
|
You can read what the inventor of the language, Bjarne Stroustrup, thinks about this right here[^]. No-one can give you a better explanation than him.
|
|
|
|
|
Great link! The explanations are even better than those found in Stroustrup's 'The C++ Programming Language' (that's what I checked, I was especially curious about :? and am somewhat disappointed that there isn't even a good reason against overloading it. I could think of a good use or two...)
|
|
|
|
|
The entire page is a good resource.
In the next version of the standard I'm looking forward to see overloading of the new operators:
; - ) and : - P
|
|
|
|
|
The mentioned operators are used for only one purpose. Example in c++ the '.' operator used only for accessing member functions. (so there is no use of overloading '.' )
.
::
?:
But the symbols (+,- and etc..) are used to add numbers and objects .
Ex:
By default '+' operators are used for adding the numbers only and not the objects
(we are overloading the '+' operator to add the objects )
In c++ operator overloading takes the meaning as below
Operator Overloading: customize the operator to do other operations also(other than default operation).
clear?
|
|
|
|
|
The documentation states the mmioxxxx provides for unbuffered and buffered files.
The CFile supports only unbuffered files.
I am sending the data retrieved by wave API ( from buffer) to the mmioxxxx file.
So do I need mmioxxxx or not?
I am "doing" MFC in VC++
Any contructive help will be as always appreciated.
Cheers
Vaclav
|
|
|
|
|
Vaclav_Sal wrote: What are the basic benefits of using mmioxxxx “file” functions as opposed to “plain “ MFC CFile?
None.
THe mmioOpen docs also state "This function is deprecated. Applications should call CreateFile or CreateFileEx to create or open files. "
CreateFile or CreateFileEx are used in the windows implementations of most standard library and MFC file classes.
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
Thanks again Mark.
Since I got my wave API going I 'll tackle this mmioxxx.
I do not remember but I think I done CFile before so it should not be much of a struggle this time.
I think I picked this mmioxxxx because the guy I copied it from build the wave file header and really did not explained why it was build that way. Most of the time when I use someone else program like that ( poorly documented) I get burned in the long run!
For example the stuff I used for wave hardly checks the functions returns. I think that is not very good programming style.
I think I need to read up on buffered and unbuffered files too.
Vaclav
|
|
|
|
|
Hi guys. I am stuck again with IOCP again. The problem is that, i just cannot create more then one worker thread. If i'll create more then one worker thread, for example 10 and on the other side there are 10 client connections, everything crashes in a random places, or it crashes because buffer for WSARecv is not allocated while in debugger i can see perfectly allocated buffer, or it crashes because socket is invalid - i just dont get it. While it is only one thread - it is working perfectly, when there more threads, it becomes unstable, and when there are 10 or more, it crashes after 1 second. Is there some magic trick i am missing again?
Thanks
011011010110000101100011011010000110100101101110
0110010101110011
|
|
|
|
|
|
Could only guess without seeing the code.
Some comments and random thoughts though...
The IOCP knows nothing about how many threads there are beyond how many are waiting on ::GetQueuedCompletionStatus().
There's no correlation between number of sockets (one for each client) associated with the IOCP and the number of worker threads. In fact, one thread per client is wrong and exactly what IOCPs are meant to eliminate.
So something is up in your code (obviously? ).
You can't share completion packets (OVERLAPPED structs) between sockets.
If the threads are accessing any common data objects then synchronization must be used.
For what it's worth, here's an example of an OVERLAPPED struct from one of my apps. Maybe it will spark something on your end...
Notes:
CClientConnection is a class that holds client information and also holds the socket handle and associated information.
pData is the I/O buffer, and is reallocated for each I/O operation. In my protocol I send a header of a known size first. That header has the number of following data bytes to expect.
dwDataLength and dwDataLengthProcessed are used tohandle situations where a single WSASend/WSARecv call doesn't process the total number of bytes requested. This MUST be done! There's no guarantee send and recv operations will send or receive all the bytes in one call. Successful completion could mean just a single byte!
#define OVERLAPPEDOP_NOOP 0
#define OVERLAPPEDOP_SOCKACCEPT 1 // CompletionKey = SOCKET, pData = 0
#define OVERLAPPEDOP_SOCKSEND 2 // CompletionKey = SOCKET, pData = NETCOMMPACKET*
#define OVERLAPPEDOP_SOCKRECVHEADER 3 // CompletionKey = SOCKET, pData = NETPACKETHEADER*
#define OVERLAPPEDOP_SOCKRECVPACKET 4 // CompletionKey = SOCKET, pData = NETCOMMPACKET*
#define OVERLAPPEDOP_EXITTHREAD 5 // CompletionKey = 0
#define MANAGEROP_ADDCLIENTCONNECTION 1 // pData = NEWUSERSOCKETINFO*
#define MANAGEROP_REMOVECLIENTCONNECTION 2 // lParam1 = CClientConnection*
#define MANAGEROP_REMOVEIOCPTHREAD 3 // lParam1 = CIOCPHandlerThread*
#define MANAGEROP_BROADCASTMESSAGE 4 // lParam1 = NETCOMMPACKETLITE* (alloc'd as BYTE*), lParam2 = CClientConnection* client to exclude
#pragma pack( push, SRVRMGR_OVERLAPPEDpack, 1 )
struct SRVRMGR_OVERLAPPED
{
OVERLAPPED Overlapped;
DWORD dwOpCode;
CClientConnection *pClientConnection;
LPARAM lParam1;
LPARAM lParam2;
DWORD dwDataLength;
DWORD dwDataLengthProcessed;
BYTE *pData;
SRVRMGR_OVERLAPPED() {memset(this, 0, sizeof(SRVRMGR_OVERLAPPED));}
};
#pragma pack( pop, SRVRMGR_OVERLAPPEDpack)
typedef CTypedPtrList<CPtrList, SRVRMGR_OVERLAPPED*> SRVRMGR_OVERLAPPEDPtrList;
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
Hey Mark. The worst thing is, i am sure that i am doing everything the exact same way but something is always wrong. I can give you the code only if i could send it to you - it is a solution with 5 projects and there are a LOT of lines, if you could take a look at it and point out mistakes i would appreciate it so much!!! (because i desperately need help with this ), can i ask you for this? please? My email: info[at]machinized[dot]com or maybe you can post yours, then i can send you the code. I am in pain
011011010110000101100011011010000110100101101110
0110010101110011
|
|
|
|
|
Here is a code, in short:
1. Extended overlapped:
struct IOContext
{
WSAOVERLAPPED m_Overlapped;
enum IOOperation
{
IOAccept,
IORead,
IOWrite,
IOConnect,
IODisconnect,
IODefault,
IOTerminate,
IOTerminateStopService
};
IOOperation m_IOOperation;
IOSocket * m_pSocket;
LPBYTE m_pbIoRecvBuffer;
DWORD m_cbIoRecvBuffer;
DWORD m_sbIoRecvBuffer;
LPBYTE m_pbIoSendBuffer;
DWORD m_cbIoSendBuffer;
DWORD m_sbIoSendBuffer;
bool GrowRecvBuffer();
bool FlushRecvBuffer();
bool GrowSendBuffer();
bool FlushSendBuffer();
bool AllocSendBuffer(DWORD dwSize);
}
bool IOContext::GrowRecvBuffer()
{
m_sbIoRecvBuffer += 2048;
m_pbIoRecvBuffer = (LPBYTE)::realloc(m_pbIoRecvBuffer,
m_sbIoRecvBuffer);
if(m_pbIoRecvBuffer == NULL)
{
return false;
}
return true;
}
bool IOContext::FlushRecvBuffer()
{
m_sbIoRecvBuffer = 0;
m_cbIoRecvBuffer = 0;
if(m_pbIoRecvBuffer)
{
::free(m_pbIoRecvBuffer);
m_pbIoRecvBuffer = NULL;
}
return true;
}
bool IOContext::GrowSendBuffer()
{
return true;
}
bool IOContext::FlushSendBuffer()
{
m_cbIoSendBuffer = 0;
m_sbIoSendBuffer = 0;
if(m_pbIoSendBuffer)
{
::free(m_pbIoSendBuffer);
m_pbIoSendBuffer = NULL;
}
return true;
}
bool IOContext::AllocSendBuffer(DWORD dwSize)
{
m_sbIoSendBuffer = dwSize;
if(m_pbIoSendBuffer)
{
::free(m_pbIoSendBuffer);
m_pbIoSendBuffer = NULL;
}
m_pbIoSendBuffer = new BYTE[m_sbIoSendBuffer];
return m_pbIoSendBuffer ? true : false;
}
2. Creating a worker thread, bind listen are just regular. Next is accept function, which is called when FD_ACCEPT event occurs:
int myclass::StreamAccept()
{
int WSAStatus = 0;
DWORD dwFlags = 0;
IOContext * pIoContextEx = new IOContext();
try
{
::RtlSecureZeroMemory(pIoContextEx, sizeof(IOContext));
if(m_bCorePortUpdated == false)
{
this->m_pCorePort->Update(m_pCoreSocket->Socket(), (ULONG_PTR)pIoContextEx);
m_bCorePortUpdated = true;
}
pIoContextEx->m_pSocket = m_pCoreSocket->WSAAccept(NULL, NULL);
this->UpdateCorePort(pIoContextEx->m_pSocket, pIoContextEx);
pIoContextEx->m_IOOperation = pIoContextEx->IORead;
if(pIoContextEx->m_sbIoRecvBuffer <= pIoContextEx->m_cbIoRecvBuffer)
{
pIoContextEx->GrowRecvBuffer();
}
WSAStatus = pIoContextEx->m_pSocket->WSARecv(pIoContextEx->m_pbIoRecvBuffer,
pIoContextEx->m_sbIoRecvBuffer,
&pIoContextEx->m_dwBytesTransfered,
&dwFlags,
&pIoContextEx->m_Overlapped);
}
catch(Exception &ex)
{
::MessageBox(0, ex.ErrorString(), NULL, 0);
}
if(WSAStatus == SOCKET_ERROR && ::WSAGetLastError() != ERROR_IO_PENDING)
{
throw Exception(::WSAGetLastError(), TEXT(__FILE__), TEXT(__FUNCTION__), __LINE__);
}
return WSAStatus;
}
3. At this moment control goes to worker thread, which begins this way:
IOComPort * pIOComPort = (IOComPort *)lpParam;
IOContext * pIOContext = NULL;
IOContext * pIOContextCasted = NULL;
LPWSAOVERLAPPED Overlapped = NULL;
DWORD dwBytesTransfered = 0;
try
{
while(true)
{
BOOL bRet = pIOComPort->GetQueuedCompletionStatus(&dwBytesTransfered,
(PULONG_PTR)&pIOContext,
(LPOVERLAPPED *)&Overlapped,
-1);
pIOContextCasted = (IOContext *)Overlapped;
case pIOContextCasted->IORead:
{
pIOContextCasted->m_dwBytesTransfered = dwBytesTransfered;
OnStreamRecved(pIOContextCasted, pIOComPort);
}
break;
5. Then we are going to OnStreamRecved.
int myclass::OnStreamRecved(IOContext * pIoContext, IOComPort * pIoComPort)
{
DWORD dwLastError = ERROR_SUCCESS;
int WSAStatus = 0;
CGuiPrintf::Inst()->PrintfAppend(TEXT("Total bytes transfered: %d\r\n"), pIoContext->m_dwBytesTransfered);
if(pIoContext->m_dwBytesTransfered != 0)
{
pIoContext->m_cbIoRecvBuffer += pIoContext->m_dwBytesTransfered;
}
if(!LastPacket( pIoContext->m_pbIoRecvBuffer,
&pIoContext->m_cbIoRecvBuffer,
pIoContext->m_sbIoRecvBuffer))
{
CGuiPrintf::Inst()->PrintfAppend(TEXT("Need to fetch more data!\r\n"));
DWORD dwFlags = 0;
if(pIoContext->m_sbIoRecvBuffer <= pIoContext->m_cbIoRecvBuffer)
{
pIoContext->GrowRecvBuffer();
}
pIoContext->m_IOOperation = pIoContext->IORead;
try
{
WSAStatus = pIoContext->m_pSocket->WSARecv( pIoContext->m_pbIoRecvBuffer + pIoContext->m_cbIoRecvBuffer,
pIoContext->m_sbIoRecvBuffer - pIoContext->m_cbIoRecvBuffer,
&pIoContext->m_dwBytesTransfered,
&dwFlags,
&pIoContext->m_Overlapped);
}
catch(Exception &ex)
{
CGuiPrintf::Inst()->PrintfAppend(TEXT("%s\r\n"), ex.ErrorString());
}
if(WSAStatus == SOCKET_ERROR && ::WSAGetLastError() != WSA_IO_PENDING)
{
return OnStreamDefault(pIoContext, pIoComPort);
}
return WSAStatus;
}
if(m_bLogTransmition)
{
CGuiPrintf::Inst()->PrintfAppend(
TEXT("CLIENT [%s : %d] SENT THIS: %s\r\n"),
::inet_ntoa(pIoContext->m_remote), pIoContext->m_port_remote,
(char *)pIoContext->m_pbIoRecvBuffer);
}
::RtlSecureZeroMemory(&pIoContext->m_Overlapped, sizeof(pIoContext->m_Overlapped));
pIoContext->m_IOOperation = pIoContext->IOWrite;
BYTE bRes[] = " - server recieved.";
DWORD dwRespSize = pIoContext->m_cbIoRecvBuffer + sizeof(bRes) + 1;
pIoContext->AllocSendBuffer(dwRespSize);
::RtlCopyMemory(pIoContext->m_pbIoSendBuffer,
pIoContext->m_pbIoRecvBuffer,
pIoContext->m_cbIoRecvBuffer);
::RtlCopyMemory(pIoContext->m_pbIoSendBuffer + pIoContext->m_cbIoRecvBuffer,
bRes,
sizeof(bRes));
try
{
WSAStatus = pIoContext->m_pSocket->WSASend(pIoContext->m_pbIoSendBuffer,
pIoContext->m_sbIoSendBuffer,
&pIoContext->m_dwBytesTransfered,
0,
&pIoContext->m_Overlapped);
}
catch(Exception &ex)
{
CGuiPrintf::Inst()->PrintfAppend(TEXT("%s\r\n"), ex.ErrorString());
}
pIoContext->FlushRecvBuffer();
if(WSAStatus == SOCKET_ERROR && ::WSAGetLastError() != ERROR_IO_PENDING)
{
return OnStreamDefault(pIoContext, pIoComPort);
}
return WSAStatus;
}
And in this above function everything crashes, while it tries to allocate recv buffer, it returns some 0xfefefe value, sometimes NULL, some strange things anyway
I am creating 100 worker (server) threads and 100 clients connections, client send simple text string to a server and server responds with another text string. But in this above function it crashes while trying to allocate some memory. I am just giving up...
011011010110000101100011011010000110100101101110
0110010101110011
|
|
|
|
|
Before I look any further than the I/O buffer code...
It looks like you have a mix of ::free() and "new" calls for allocation operations. Those can't be mixed. In c++ I would just use new/delete and forget the realloc stuff, but you're free to use the c library functions if you prefer, but you can't mix in new/delete!
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
Thats basically doesnt matter, you can mix it. What you cannot is HeapAlloc and free or malloc and HeapFree for example. It seems to me that its kind of not possible to have memory allocations with IOCP. No matter what i do, app always crashes randomly. And there is always heap corruption. If there is static buffer - 1000 connections without a problem, if there is dynamic memory allocation - even one connection crashes.
011011010110000101100011011010000110100101101110
0110010101110011
|
|
|
|
|