Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Using CWinThread in MFC apps

196 views
Skip to first unread message

Jack

unread,
Aug 2, 2009, 9:38:31 PM8/2/09
to
Hello,
Do I have to call AfxBeginThread inside CMyThread
(derived from CWinThread)::InitInstance function,
How can I access the document/view objects?
If I put these objects into the CMyThread class,
The object cannot be persistant..
Any ideas
Thanks
Jack


Scott McPhillips [MVP]

unread,
Aug 2, 2009, 11:25:25 PM8/2/09
to
"Jack" <j...@knight.com> wrote in message
news:eKrGVs9E...@TK2MSFTNGP04.phx.gbl...


If you call AfxBeginThread with a class derived from CWinThread it works the
other way around. As a result of calling AfxBeginThread the CWinThread's
InitInstance function is called (executing in the new thread).

The other form of AfxBeginThread, where you pass a static function, simply
runs the function in the new thread. The LPVOID parameter of AfxBeginThread
can be used to pass anything you want to the thread function. Such as a
struct containing data and pointers to the document.

--
Scott McPhillips [VC++ MVP]

Joseph M. Newcomer

unread,
Aug 3, 2009, 12:07:49 AM8/3/09
to
See below...

On Mon, 3 Aug 2009 09:38:31 +0800, "Jack" <j...@knight.com> wrote:

>Hello,
>Do I have to call AfxBeginThread inside CMyThread
>(derived from CWinThread)::InitInstance function,

****
If you want a UI thread, yes. If you want a worker thread, no. So you have not said what
kind of thread you want.

Be careful what you do in InitInstance. For example, it would inappropriate to put an
infinite loop there, or a loop that breaks out only for termination. In such a case you
would want a worker thread, not a UI thread. InitInstance is used only to initialize a UI
thread, prior to running its message pump.
****


>How can I access the document/view objects?

****
You would not want to access view objects. You may or may not want to access document
objects, but if you do, you would put a pointer to your document instance in the
CWinThread object (for UI threads) or pass it in via a struct/class as the only parameter
to the worker thread.
****


>If I put these objects into the CMyThread class,
>The object cannot be persistant..

****
Why would you ever want CMyThread to be "persistent", that is, saved across executions?
This doesn't even make sense. You can safely assume that any application architecture
that tries to do this is erroneous.

This question is at best confusing as stated, and at worst represents an untenable design.
You would need to explain more clearly what you are trying to do.
joe
****
>Any ideas
>Thanks
>Jack
>
Joseph M. Newcomer [MVP]
email: newc...@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm

Joseph M. Newcomer

unread,
Aug 3, 2009, 12:11:46 AM8/3/09
to
In rereading the question, I find it even more confusing. AfxBeginThread could not be
called from within the InitInstance function because the InitInstance function is called
in the context of the thread, and the thread has to be started with either AfxBeginThread
or CWinThread::Create. If you call AfxBeginThread from within InitInstance, you will
create *another* thread.
joe

On Mon, 3 Aug 2009 09:38:31 +0800, "Jack" <j...@knight.com> wrote:

Jack

unread,
Aug 3, 2009, 3:28:56 AM8/3/09
to
Thanks guys for the help..
I ran into another problem now.
My CSocket::OnReceive is never called.
I searched the net and some website suggested
that I was stucked in a loop instead of the message pump
I looked here and there for a couple of hours but still
couldn't find the bug...
Could you please help?

[code]
// Socket.cpp : implementation file

//

#include "stdafx.h"

#include "CDemo.h"

#include "Socket.h"

#include ".\socket.h"

class CCDemoDoc;

UINT __cdecl Sock_Handler(LPVOID arg);

SOCKET hConnected;

// cSocket

cSocket::cSocket()

{

OutputDebugString("cSocket::cSocket\n");

}

cSocket::cSocket(CCDemoDoc *pDoc)

{

m_Doc = pDoc;

}

cSocket::~cSocket()

{

OutputDebugString("cSocket::~cSocket\n");

}

// cSocket member functions

void cSocket::OnAccept(int nErrorCode)

{

OutputDebugString("cSocket::OnAccept\n");

//Accept(this);

Attach(hConnected);

// TODO: Add your specialized code here and/or call the base class

AfxBeginThread(Sock_Handler, this);

CSocket::OnAccept(nErrorCode);

}

void cSocket::OnClose(int nErrorCode)

{

OutputDebugString("cSocket::OnClose\n");

// TODO: Add your specialized code here and/or call the base class

CSocket::OnClose(nErrorCode);

}

void cSocket::OnConnect(int nErrorCode)

{

OutputDebugString("cSocket::OnConnect\n");

// TODO: Add your specialized code here and/or call the base class

CSocket::OnConnect(nErrorCode);

}

void cSocket::OnOutOfBandData(int nErrorCode)

{

OutputDebugString("cSocket::OnOutOfBandData\n");

// TODO: Add your specialized code here and/or call the base class

CSocket::OnOutOfBandData(nErrorCode);

}

void cSocket::OnReceive(int nErrorCode)

{

OutputDebugString("cSocket::OnReceive\n");


char buff[4096];

int nRead;

nRead = Receive(buff, 4096);

if (nRead != SOCKET_ERROR)

{

if (nRead)

{

buff[nRead] = 0;

CString szTemp(buff);

// ((CMsocsDlg*)m_pDlg)->m_strRecv += szTemp;

// ((CMsocsDlg*)m_pDlg)->UpdateData(FALSE);

// if (szTemp.CompareNoCase("bye") == 0 ) ShutDown();

}

else Close();

}

else

{

wsprintf (buff, "Error number is %d", GetLastError());

AfxMessageBox (buff);

}


CSocket::OnReceive(nErrorCode);

// TODO: Add your specialized code here and/or call the base class


}

void cSocket::OnSend(int nErrorCode)

{

OutputDebugString("cSocket::OnSend\n");

// TODO: Add your specialized code here and/or call the base class

CSocket::OnSend(nErrorCode);

}

int cSocket::Receive(void* lpBuf, int nBufLen, int nFlags)

{

OutputDebugString("cSocket::Receive\n");

// TODO: Add your specialized code here and/or call the base class

return CSocket::Receive(lpBuf, nBufLen, nFlags);

}

int cSocket::Send(const void* lpBuf, int nBufLen, int nFlags)

{

OutputDebugString("cSocket::Send\n");

// TODO: Add your specialized code here and/or call the base class

return CSocket::Send(lpBuf, nBufLen, nFlags);

}

BOOL cSocket::OnMessagePending()

{

OutputDebugString("cSocket::OnMessagePending\n");

// TODO: Add your specialized code here and/or call the base class

return CSocket::OnMessagePending();

}

//////////////////////////////////////

UINT __cdecl Sock_Handler(LPVOID arg)

{

cSocket *pSock = (cSocket*) arg;

while(true)

{

if (!pSock->buff.empty())

{

// pSock->CopyDataToPacket();

pSock->buff.clear();

}


Sleep(500);


}

return 0;

}


[/code]


Jack

unread,
Aug 3, 2009, 3:36:30 AM8/3/09
to

One more thing forgot to mention
was that the program didn't seem to be stucked in a loop, but exited
immediately with the calls to the destructors.
Thanks
Jack


Scott McPhillips [MVP]

unread,
Aug 3, 2009, 10:00:35 AM8/3/09
to
"Jack" <j...@knight.com> wrote in message
news:O0mKX0AF...@TK2MSFTNGP05.phx.gbl...


It's not clear what you are trying to do. Is the socket created in the main
thread? Are you trying to handle its notifications in the worker thread?
The MSDN site has several code examples and articles for CSocket and
CAsyncSocket, including one that shows how to transfer the socket's thread.

Joseph M. Newcomer

unread,
Aug 3, 2009, 1:12:19 PM8/3/09
to
You cannot put socket handlers in a worker thread. See my essay on multithreaded socket
handlers.

More below...

On Mon, 3 Aug 2009 15:28:56 +0800, "Jack" <j...@knight.com> wrote:

>Thanks guys for the help..
>I ran into another problem now.
>My CSocket::OnReceive is never called.
>I searched the net and some website suggested
>that I was stucked in a loop instead of the message pump
>I looked here and there for a couple of hours but still
>couldn't find the bug...
>Could you please help?
>
>[code]
>// Socket.cpp : implementation file
>
>//
>
>#include "stdafx.h"
>
>#include "CDemo.h"
>
>#include "Socket.h"
>
>#include ".\socket.h"
>
>class CCDemoDoc;
>
>UINT __cdecl Sock_Handler(LPVOID arg);
>
>SOCKET hConnected;

****
This instantly says "SERIOUS DESIGN ERROR!" There should be no global variables used for
this purpose.
****


>
>// cSocket
>
>cSocket::cSocket()
>
>{
>
>OutputDebugString("cSocket::cSocket\n");
>
>}
>
>cSocket::cSocket(CCDemoDoc *pDoc)
>
>{
>
>m_Doc = pDoc;
>
>}
>
>cSocket::~cSocket()
>
>{
>
>OutputDebugString("cSocket::~cSocket\n");
>
>}
>
>
>
>// cSocket member functions
>
>void cSocket::OnAccept(int nErrorCode)
>
>{
>
>OutputDebugString("cSocket::OnAccept\n");
>
>//Accept(this);
>
>Attach(hConnected);

****
Why are you doing this? It makes no sense.
****


>
>// TODO: Add your specialized code here and/or call the base class
>
>AfxBeginThread(Sock_Handler, this);

*****
You cannot put sockets in a worker thread. You must use a UI thread.
*****


>
>CSocket::OnAccept(nErrorCode);
>
>}
>
>void cSocket::OnClose(int nErrorCode)
>
>{
>
>OutputDebugString("cSocket::OnClose\n");
>
>// TODO: Add your specialized code here and/or call the base class
>
>CSocket::OnClose(nErrorCode);
>
>}
>
>void cSocket::OnConnect(int nErrorCode)
>
>{
>
>OutputDebugString("cSocket::OnConnect\n");
>
>// TODO: Add your specialized code here and/or call the base class
>
>CSocket::OnConnect(nErrorCode);
>
>}
>
>void cSocket::OnOutOfBandData(int nErrorCode)
>
>{
>
>OutputDebugString("cSocket::OnOutOfBandData\n");
>
>// TODO: Add your specialized code here and/or call the base class
>
>CSocket::OnOutOfBandData(nErrorCode);
>
>}
>
>void cSocket::OnReceive(int nErrorCode)
>
>{
>
>OutputDebugString("cSocket::OnReceive\n");
>
>
>char buff[4096];
>
>int nRead;
>
>nRead = Receive(buff, 4096);
>
>if (nRead != SOCKET_ERROR)
>
>{
>
>if (nRead)

****
I presume you mean
if(nRead != 0)
****
>
>{
>
>buff[nRead] = 0;
****
If you read 4096 bytes, this puts the 0 in the 4097th position of the 4096-long array.
Note that you must receive sizeof(buff)-1 (do NOT repeat the constant in two places; use
sizeof or use a #define or const UINT to declare the size)
****
>
>CString szTemp(buff);
****
Note that if you are a Unicode app, this will create a Unicode string. Note that this
will not work properly if the string is encoded in UTF-8, which is the recommended best
practice.
****


>
>// ((CMsocsDlg*)m_pDlg)->m_strRecv += szTemp;
>
>// ((CMsocsDlg*)m_pDlg)->UpdateData(FALSE);

****
The above lines would ALWAYS be erroneous. You CANNOT call UpdateData from a secondary
thread, worker or UI. This would be a serious mistake, and these lines should simply be
removed from the code lest there be a temptation to uncomment them.
****


>
>// if (szTemp.CompareNoCase("bye") == 0 ) ShutDown();

****
Why would you expect this to EVER work under ANY conditions imaginable? If you are
receiving 4096 bytes, you might well get

This is a test message\nThis is another message\nThis is yet another message\nbye

There is NO CORRELATION between the data packet size sent by a Send and the number of
bytes received by a Receive. The only guarantee you have is that the Receive will
eventually receive all the bytes sent by a successful Send, with no duplicates, in order,
with no missing data. Otherwise, you can send

This
is
a
test\n
This
is
another\n

and your first Receive might return

This is a test\nThis

and the next Receive will receive
is another\n

Or you might send

This is a test\nThis is another\n

and receive

This is
followed by
a test\nThis is another\n

Any delusion that there will in any way whatsoever be a correlation between the length of
packets sent and those received is exactly that. It is your responsibility, if the
packets have some kind of structure, to reassemble them into something that has meaning.
joe
****


>
>}
>
>else Close();
>
>}
>
>else
>
>{
>
>wsprintf (buff, "Error number is %d", GetLastError());

****
You should safely assume that sprintf, wsprintf, etc. are meaningless noise, and should
NEVER be used in practice. There is no excuse for using it here! The correct code would
be

CString msg;
msg.Format(_T("Error number is %d"), GetLastError());
****


>
>AfxMessageBox (buff);
>
>}
>
>
>CSocket::OnReceive(nErrorCode);
>
>// TODO: Add your specialized code here and/or call the base class
>
>
>}
>
>void cSocket::OnSend(int nErrorCode)
>
>{
>
>OutputDebugString("cSocket::OnSend\n");
>
>// TODO: Add your specialized code here and/or call the base class
>
>CSocket::OnSend(nErrorCode);
>
>}
>
>int cSocket::Receive(void* lpBuf, int nBufLen, int nFlags)
>
>{
>
>OutputDebugString("cSocket::Receive\n");
>
>// TODO: Add your specialized code here and/or call the base class
>
>return CSocket::Receive(lpBuf, nBufLen, nFlags);
>
>}
>
>int cSocket::Send(const void* lpBuf, int nBufLen, int nFlags)
>
>{
>
>OutputDebugString("cSocket::Send\n");
>
>// TODO: Add your specialized code here and/or call the base class
>
>return CSocket::Send(lpBuf, nBufLen, nFlags);
>
>}
>
>BOOL cSocket::OnMessagePending()
>
>{
>
>OutputDebugString("cSocket::OnMessagePending\n");
>
>// TODO: Add your specialized code here and/or call the base class
>
>return CSocket::OnMessagePending();
>
>}
>
>//////////////////////////////////////
>
>UINT __cdecl Sock_Handler(LPVOID arg)
>
>{
>
>cSocket *pSock = (cSocket*) arg;
>
>while(true)
>
>{
>
>if (!pSock->buff.empty())

****
I have no idea what this is supposed to be doing, but it is safe to assume that this code
is erroneous. I can't imagine what value this has.

Given you have a socket in a UI thread, this is deeply erroneous, since there is no
possible way the buffer can ever be set.

In a UI thread, there would never be a reason to test the buffer size like this; the
OnReceive handler would be responsible for creating the packet and sending it to the
receiving thread, and it would not make sense to put that code anywhere else.
****


>
>{
>
>// pSock->CopyDataToPacket();
>
>pSock->buff.clear();
>
>}
>
>
>Sleep(500);

****
First rule: any thread that has a Sleep in it is wrong.
Second rule: if you think this is right, consult the first rule
Third rule: The exceptions are amazingly rare and apply only under fairly exotic
conditions, which this is not an instance of.

Therefore, you can safely assume that putting a Sleep in a thread is always a mistake.
Note that a thread must work *correctly* without any Sleep() calls.
joe
****
>
>
>}
>
>return 0;
>
>}
>
>
>[/code]

Stephen Myers

unread,
Aug 3, 2009, 1:25:07 PM8/3/09
to


You've created a worker thread. A worker thread does not have a message
pump so the socket can't notify the thread that there's data available
(OnReceive).

Instead you should derive a class based on CWinThread and use the other
constructor
pThread = static_cast<MyThread>(AfxBeginThread(RUNTIME_CLASS(MyThread));

Joe has some excellent articles on his site.

Steve

Jack

unread,
Aug 3, 2009, 10:41:29 PM8/3/09
to
Thank you all the guys, trying to digest now!!
Jack


0 new messages