|
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
|
|
|
|
|
csrss wrote: Thats basically doesnt matter, you can mix it.
What??? "Basically", it does matter. In practice, however, it may not matter... at least maybe currently. It's a horrible programming practice to mix memory allocation function families. There is absolutely NO guarantee that any given library implementation versions will remain compatible. But if you like to live dangerously...
csrss wrote: It seems to me that its kind of not possible to have memory allocations with IOCP
IOCP doesn't know anything about memory allocations or your buffers or anything. You are responsible for that and all standard multithread rules apply.
Regardless of all that, it should be relatively easy to debug. Your heap is getting trashed. Running in debugger when it crashes you should be able to go to any thread and check call stacks to see where it's failing.
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
Hi Experts,
I need your help to solve a problem. Problem is to create a dynamic tree in memory.
I have a node with 2 field 1. Self Record Number and 2. Parent Record Number
I need to create a hierarchy (Tree) based on above information. Any node can come in any sequence. There is no rule defined for hirerchy.
How to set the node at run time so that I can create a correct child-parent hierarchy?
|
|
|
|
|
The "parent" should point to the parent and the "self" should point to the sibling.
But it is a very poor implementation, difficult to walk and maintain (who are the children of a given parent? you should keep a list of the "world" to scan!).
Hierarchies normally requires more pointers:
- to the parent
- to the first child (and eventually to the last)
- to the next sibling (and eventually the previous)
2 bugs found.
> recompile ...
65534 bugs found.
|
|
|
|
|
john5632 wrote: I have a node with 2 field 1. Self Record Number and 2. Parent Record Number
You can add your nodes to a vector, a linked list or a map. Then by definition you already have a tree, as long as you keep the constraint of not adding any loops, and keeping a single root node.
It all depends on what you want to do with it in the end. If you need fast look-up, then look at Emilios suggestion above. Otherwise, go simple.
|
|
|
|
|
Hi all, I need to retrieve image information from an CMenu item, below is my code, but exception occurs at last line when I call GetHBITMAP().
I suspect the dwItemData I retrieved is NOT a Bitmap*.
I suspect the menu I am working on is build with MFT_OWNERDRAW option.
// get the menu item icon
MENUITEMINFO mii;
mii.cbSize = sizeof(MENUITEMINFO);
mii.fMask = MIIM_FTYPE;
mii.fType = MFT_OWNERDRAW;
pMenu->GetMenuItemInfo(i, &mii, TRUE/*1st param = item position*/);
HBITMAP hbm = NULL;
Gdiplus::Bitmap* pMI = (Gdiplus::Bitmap*)mii.dwItemData;
Gdiplus::Status status = pMI->GetHBITMAP(Gdiplus::Color(0, 255, 255, 255), &hbm);
Thanks in advance!
modified on Wednesday, July 6, 2011 9:50 PM
|
|
|
|
|
I don't see a call to GetMenuItemInfo() [^], so the contents of dwItemData will not be valid.
The best things in life are not things.
|
|
|
|
|
Sorry I removed that line with some other comments after pasting here. Added already. In the actual code I did call GetMenuItemInfo(), thanks!
|
|
|
|
|
nate31 wrote: Gdiplus::Bitmap* pMI = (Gdiplus::Bitmap*)mii.dwItemData;
Since dwItemData has not been initialized, what value do you suppose pMI has?
"One man's wage rise is another man's price increase." - Harold Wilson
"Fireproof doesn't mean the fire will never come. It means when the fire comes that you will be able to withstand it." - Michael Simmons
"Some people are making such thorough preparation for rainy days that they aren't enjoying today's sunshine." - William Feather
|
|
|
|
|
Can you point out what I should do here? Thanks!
|
|
|
|
|
Start with something like:
MENUITEMINFO mii = {0};
mii.cbSize = sizeof(MENUITEMINFO);
mii.fMask = MIIM_FTYPE;
mii.fType = MFT_OWNERDRAW;
if (pMenu->GetMenuItemInfo(i, &mii, TRUE ))
{
Gdiplus::Bitmap *pMI = (Gdiplus::Bitmap *) mii.dwItemData;
if (pMI != NULL)
{
HBITMAP hbm = NULL;
Gdiplus::Status status = pMI->GetHBITMAP(Gdiplus::Color(0, 255, 255, 255), &hbm);
if (status == Status::Ok)
;
}
else
ASSERT(FALSE);
}
else
dwError = GetLastError();
"One man's wage rise is another man's price increase." - Harold Wilson
"Fireproof doesn't mean the fire will never come. It means when the fire comes that you will be able to withstand it." - Michael Simmons
"Some people are making such thorough preparation for rainy days that they aren't enjoying today's sunshine." - William Feather
|
|
|
|
|
Hi developers,
I am using a wrapper class (Taken from Codeproject), in which ADO connectivity has been used,
CADORecordset rsAccessMedia(&theApp.m_pDbHompath);
CString strQuery;
strQuery.Format( _T("select * from %s where ID = %d"), m_strTable, lngcurrItemID );
rsAccessMedia.Open( strQuery, CADORecordset::openQuery );
bool bIsOK = true;
if(rsAccessMedia.IsEOF()) //If Record not found for the selected( draaged ) media
bIsOK = false;
rsAccessMedia.Close();
At the last line application getting crashed. Connection is proper, but I don't know why it is being crashed.
Pls help me out.
Thanks.
|
|
|
|
|
I would not do this
strQuery.Format( _T("select * from %s where ID = %d"), m_strTable, lngcurrItemID );
unless m_strTable is a char* or const char* (or wide version thereof)
use
strQuery.Format( _T("select * from %s where ID = %d"), (LPCTSTR)m_strTable, lngcurrItemID );
to ensure proper interpretation of the argument.
Otherwise, it doesn't look too bad. The piece of code you supplied, is that all you have to run to get the error?
Edit: I'm assuming m_strTable is a CString.
|
|
|
|
|
Yes, m_strTable is a CString variable.
Then what's wrong with the query.
Is might be becoz of improper connection
|
|
|
|
|
The CString does not only contain a pointer to a character array, but also more information such as allocation size and length of current data. If you use a CString as an argument you will push all that to the stack, when in fact you only want the pointer to the character array on the stack, as described by the format specifiers to CString::Format(). You will simply mess up the arguments/stack. Do the conversion I suggested in the answer above to avoid this.
This is one reason to avoid variable arguments whenever possible. The compiler cannot perform type checks.
Does your code still fail?
|
|
|
|
|
Hi all,
this error comes when i am using win32 dll in c# application.
An unhandled exception of type 'System.BadImageFormatException' occurred in Test.exe
Additional information: An attempt was made to load a program with an incorrect format. (Exception from HRESULT: 0x8007000B)
please help me for this.
thanks in advance.
|
|
|
|
|
Please ask in the C# forum.
|
|
|
|
|
Are you building both the binaries on the same platform? 32 bit or 64 bit ?
|
|
|
|
|
|
Try this one, make your application run inside WoW64. For that go to the project properties, select the "build" tab and set the "platform target" to x86.
FYI : Read this.[^]
|
|
|
|
|
thanks,its working fine
but its safe and secure for further use.
is C# application work for all platform x86 and x64.
|
|
|
|
|