Click here to Skip to main content
Click here to Skip to main content

Using AfxBeginThread with class member controlling function

By , 19 Jun 2002
 

Introduction

Creating a separate thread in your application in order to execute some time consuming operations is very simple. You just call AfxBeginThread() with the appropriate parameters and that's it. But Microsoft wants the controlling function either to be a global function or to be a static class member function; which in both cases means that you don't have access to your class member variables or methods from within the controlling function. This article shows you a little trick on how to do this and keep your source OO.

Step-by-Step

  1. Create your project as usual, add your dialogs, controls and all the stuff.
  2. Create your classes for the dialogs using Class Wizard, and assign variables to your controls.
  3. For the class you want to implement multithreading, edit the header file adding the following code:
    //controlling function header
    static UINT StartThread (LPVOID param);
    
    //structure for passing to the controlling function
    typedef struct THREADSTRUCT
    {
        CThreadDemoDlg*    _this;
            //you can add here other parameters you might be interested on
    } THREADSTRUCT;
  4. In the implementation file for your class, add the following code:
    UINT CThreadDemoDlg::StartThread (LPVOID param)
    {
        THREADSTRUCT*    ts = (THREADSTRUCT*)param;
    
        //here is the time-consuming process 
        //which interacts with your dialog
        AfxMessageBox ("Thread is started!");
    
            //see the access mode to your dialog controls
        ts->_this->m_ctrl_progress.SetRange (0, 1000);  
        while (ts->_this->m_ctrl_progress.GetPos () < 1000)
        {
            Sleep(500);
            ts->_this->m_ctrl_progress.StepIt ();
        }
    
        //you can also call AfxEndThread() here
        return 1;
    }
    void CThreadDemoDlg::OnStart() 
    {
            //call the thread on a button action or menu
        THREADSTRUCT *_param = new THREADSTRUCT;
        _param->_this = this;
        AfxBeginThread (StartThread, _param);
    }
  5. Now you can test your program!

Conclusion

I hope this will be helpful for you. I've been using CodeProject for a long time and this article is the first step for payback.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Enis
Software Developer (Senior)
Romania Romania
Member
No Biography provided

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralMy vote of 1membersunilkpv28 Nov '12 - 20:27 
Too too basic and highly uninformative
GeneralMy vote of 1memberPanic2k318 Sep '09 - 17:57 
I can understand this as a example on how to force the use but more information should be present on why this is a bad idea and why the limitations exist...
GeneralTHREADSTRUCT Not NeededmemberJonathan Wood4 Feb '09 - 4:33 
As was pointed out, the code allocates a THREADSTRUCT object but fails to free it.
 
However, I don't even see why this is needed. Just pass this to the function and you have your pointer to the class instance. No additional structures, and no additional allocations.
GeneralDon't use this "trick"memberRoland_W5 Nov '08 - 11:01 
This was the first hit I got on google when searching for "afxBeginThread member function", so I feel need to make it clear that this solution is obviously flawed and incorrect.
 
As pointed out before, the proposed solution will cause a memory leak because delete on THREADSTRUCT is not called. If, however, one calls delete after AfxBeginThread, we will get an undeterministic result. For if the thread for some reason takes a long time to start, delete may be called before the static function can read the parameters in the THREADSTRUCT, and then we have no idea what the memory area the pointer points to contains.
GeneralGreat trick, thanks!!memberphilbnt5 May '08 - 22:04 
This trick is great, simple and very useful.
TXS
QuestionMulti Client Server Please Help!memberMauraV13 Oct '07 - 18:42 
Hi!
I'm trying to implement a multi-client server and when i run my code y receive an Access Violation on the ThreadProc when i call conn->Connect.Receive. The struct Conexiones is well defined? How can my ListenSocket could hear and accept new connections. This is part of my code:
 
struct Conexion *Conexiones=Conexiones=new struct Conexion [MAX_CONEXIONES];
 
void CSockDlgServer::OnAccept()
{
int i=0;
while ((im_nThreadID=Conexiones[i].Connect.m_hSocket;
 
}
UINT CSockDlgServer::ThreadProc(LPVOID _param)
{
struct Conexion * conn=(struct Conexion *) param;
char *pBuf = new char[1025];
int iBufSize=1024;
int iRecvd;
 
// recibimos el mensaje
iRecvd=conn->Connect.Receive(pBuf,iBufSize); // here is de Access Violation
if (iRecvd==SOCKET_ERROR)
{
return 1;
}
else
{
// i do some operation with a data structure
}
return 0;
}
 
Please Help Me!
QuestionUsing this method with a other class.memberCVianney9 Oct '07 - 22:25 

Hello,

I am very interested in this method, I tried to implement it but I had a problem.
The fact is, in my case, I am not using a CDialog derived class but a class like this one :
class ATL_NO_VTABLE CPropPage :
public CComObjectRootEx,
public CComCoClass,
public IPropertyPageImpl,
public CDialogImpl
{
So I can not implement the DoDataExchange function that is (I think) important to have a good behavior of the software.
The thread starts because I see the MessageBox "Thread is started!" but the progress bar is not updated with the different step of progression.
 
Is the DoDataExchange function the problem ? Somebody has other ideas ?
Thanks.
 
Vianney
 

GeneralThank you very muchmemberMember #31823345 Feb '07 - 16:31 
This program is very simple but nice !It is easy for me to study it .Thanks a lot!
from China 2007-2-6
 
LXS

GeneralHelp for OpenGL Threadmembersrinin00824 Jul '06 - 3:59 
I am doing some OpenGL drawing in MFC view.
I have a OpenGL class which is used as the base class for MFC view. Then using display lists i have tried to put the drawing on the view. But in tha case of huge point sets, the View doest respond because of openGL drawing.
 
Then i thought of using threads for openGL.Now i want to implement a thread for drawing openGL stuff.
 
I have one static UINT threadfunc(LPVOID param) and void threadfunc() declared.
Then i have tried to begin the thread.
I did not get any compilation, linker errors.
 
But i was unsuccessful in getting the drawing stuff.
 
Can anyone help me?
 

GeneralAlso on memory leakmemberchiac2 Apr '06 - 18:46 
This is a slight different question than the previous memory leak one. I have converted the demo project to Visual studio 7.1 and compiled it under the debug mode, and this is what I get when I clicked on "Start" to run the thread.
 
ThreadDemo.exe': Loaded 'C:\Program Files\Yahoo!\Messenger\msvcr71.dll', No symbols loaded.
Detected memory leaks!
Dumping objects ->
thrdcore.cpp(311) : {78} client block at 0x00326A50, subtype c0, 68 bytes long.
a CWinThread object at $00326A50, 68 bytes long
c:\code\thread2\threaddemo\threaddemodlg.cpp(196) : {77} normal block at 0x00324B80, 4 bytes long.
Data: < > E8 FD 12 00
Object dump complete.
The thread 'Win32 Thread' (0xdb4) has exited with code 0 (0x0).
The program '[3796] ThreadDemo.exe: Native' has exited with code 0 (0x0).
------------------------------------
This is very confusing. Please help
 
jiac
GeneralThanksmemberdhammeriz12 Dec '05 - 7:09 
Your idea had saved my ass.
I use it for multithread receives with sockets.
 
THANKS, man.

GeneralMemory leak on THREADSTRUCTmembersrev21 Jun '05 - 2:54 
Hi Enis,
 
Thank you so much for this little technique. I've found it very useful indeed. However, I've hit one problem which is that no matter how hard I try I can't avoid getting a memory leak when I run it.
 
The leak is always 4 bytes long and I'm convinced it's the THREADSTRUCT. I've tried to delete it but have found it virtually impossible to get rid of.
 
How and where do you delete this object? Can you help?
 
Many thanks,
 
Simon
GeneralRe: Memory leak on THREADSTRUCTsussAnonymous19 Oct '05 - 2:45 
Can't you just delete ts structure within the StartThread function; this seems logical since ts points to the memory space that was allocated.
 
-- Darin
GeneralRe: Memory leak on THREADSTRUCTmemberciyoung16 Feb '06 - 17:36 
Add "Delete ts;",Before "return 1;",It Should Be Solve Memory Leak Problem.
GeneralUnhandled ExceptionsussAnonymous26 May '04 - 2:44 
Thanks a lot. Your article really got me out of a fix. I have though 1 problem. I have a class X that instantiates a class CSerialPort (freeware).
I am spawning a thread so that I can wait for a COM event. I tried WaitEvent like so
ts->this->m_Port.WaitEvent(dwMask);
it is exceptioning at this point. Could someone tell me why that is happening and what I could do about it?
Thanks
GeneralStop Threadmemberaman20066 May '04 - 5:57 
hey
 
Tell me please how to stop the thread in between from some button click event.
 
I am using pThread->SuspendThread()
Thread is stopped but when i return to my Main form program hangs.
 
Thanks
Shailesh
GeneralRe: Stop ThreadmemberEnis6 May '04 - 6:34 
Hy,
I didn't test the exact code you wrote in your previous post, but I can sugest you a solution using Events. (the code below is typed so it might not be such accurate)
HANDLE yourEvent;
yourEvent = ::CreateEvent (NULL,  //no security
                           TRUE,  //manual reset
                           FALSE, //non-signaled initial
                           NULL   //anonymous
                           );
CWinThread* pWorkerThread = NULL;
pWorkerThread = AfxBeginThread (ThreadFunc, ...);
pWorkerThread->m_bAutoDelete = FALSE;
 
//here you terminate your thread; while your thread is running, 
//you must ::SetEvent(yourEvent) and the code below WaitForSingleObject will execute
if (::WaitForSingleObject (pWorkerThread->m_hThread, INFINITE) == WAIT_OBJECT_0)
  if (pWorkerThread != NULL)
    ::GetExitCodeThread (pWorkerThread->m_hThread, &dwExitCode);
 
CloseHandle(yourEvent);
delete pWorkerThread;
I hope this helps.
You can also check Joseph M. Newcomer's great articles about threads
(http://www.codeproject.com/threads/usingworkerthreads.asp[^])
 

 
Enis Arif
-----------
 
"I am enough of an artist to draw freely upon my imagination. Imagination is more important than knowledge. Knowledge is limited. Imagination encircles the world." (Albert Einstein)

GeneralRe: Stop Threadmemberj.v.r.25 Aug '10 - 7:47 
From PEPE2207
Hi, Enis, Recently I tried your threaddemo article and I found it works fine, but I am a bit confuse because I can not discover where is deleted the _param pointer releasing the heap memory asigned to the ts THEADSTRUCT instance that you were using the new istruction. Sincerely
GeneralStop Thread Problemmemberaman20065 May '04 - 14:52 
Hey I am using this code in my thread as
void CUploadForm::OnButtonUpload()
{
THREADSTRUCT *_param = new THREADSTRUCT;
_param->_this = this;
pThread = AfxBeginThread (StartThread,_param );
 

}
UINT CUploadForm::StartThread (LPVOID param)
{
THREADSTRUCT* ts = (THREADSTRUCT*)param;
ts->_this->PreparePostData();
AfxEndThread(0);// here
return 1;
}
 
Now i want to stop this thread process on some button click event but when return to my form my program hangs. I am stopping as:
 
void CUploadForm::OnButtonCancel()
{
 
if(pThread)
{
pThread->m_bAutoDelete = FALSE;
UINT aa = pThread->SuspendThread( );
SetDlgItemText(IDC_EDIT_RESPONSE,_T("Process Stopped by user."));
pThread = NULL;
}
 


}
 
and when i press the button to return to my main program it hangs any idea
void CUploadForm::OnButtonReturn()
{
CMainFrame* pFrame = (CMainFrame*)GetParentFrame();
pFrame->SwitchToForm(IDD_NOPDCITATION_FORM);
pFrame->SetWindowText(_T("Cite Capture"));

}
 
Please help me
 
shailesh
GeneralHELP PLEASEmemberwin32newb3 Mar '04 - 17:01 
Cry | :(( I used this example and it works fine if i do it exactly like he has. But what if i actually want to do something inside the thread. I can't.
I have member control called m_ball1 and a HICON called m_h0;
I want to update the m_ball1 within the thread but i can't.
i keep getting the error
error C2228: left of '.SetIcon' must have class/struct/union type
error C2597: illegal reference to data member 'CCash3mfcDlg::m_h0' in a static member function
 
I have everything exactly like the author of this demo has except my Classname is different I used CCash3mfcDlg.
 
I have this in the cpp. If i // it out the program works just like the demo.
What am I doing wrong cause i would really like to incorporate this into my program.
 

UINT CCash3mfcDlg::StartThread(LPVOID param)
{
    
     THREADSTRUCT*     ts = (THREADSTRUCT*)param;
    
     //here is the time-consuming process which interacts with your dialog
     AfxMessageBox ("Thread is started!");
    
     ts->_this->m_processstatus.SetRange (0, 1000);
     while (ts->_this->m_processstatus.GetPos () < 10000000)
     {
          Sleep(500);
         
////////////////////THE MENTIONED ERRORS ARE CAUSED BY THIS ADDITION////////
 
                        m_ball1.SetIcon(m_h0);
 
////////////////////////////////////////////////////////////////////////////
          ts->_this->m_processstatus.StepIt ();
     }
 
     //you can also call AfxEndThread() here
     return 1;
    
}
 
Just starting to get into Visual C++ so give me some slack please.
GeneralRe: HELP PLEASEmemberJens Winslow17 Mar '04 - 6:13 
I am just guessing here, based on my own challenges with multi-thread, but perhaps it will help you (?)
 
The multi thread functions must be static, and there are restrictions on the kinds of access static functons can have. I am guessing m_h0 is not static and therefore not directly acessible by the static multi thread func.
 
Basically a static function (and static variables) only exists once in memory, regardless of the number of times you instantiate an object from a class. This means a static function cannot know about the specific instance of an object and ita members (at least not directly.
 
I.e. if class CTest has member NotStatic, and static member Static, then
 
CTest T1;
CTest T2;
 
T1.NotStatic = 1;
T2.NotStatic = 2;
ASSERT( T1.NotStatic != T2.NotStatic ); //ok, no conflict
 
T1.Static = 1; //Static now 1
T2.Static = 2; //Static of ALL CTests now 2!!!
ASSERT( T1.Static != T2.Static ); //FAILS - CTest.Static all the same veriable.
 
A static function in CTest using NonStatic, would not directly know which instance (T1 or T2) to use, and therefore fails.
 
However, if you somehow pass the static function enough info to resolve the referencing (usually by a this pointer), you are ok.
 
Therefore you might try referencing m_h0 using the _this pointer - as far as I can see the THREADSTRUCT includes a _this pointer, which would let the static function access the specific instance of CCash3mfcDlg which holds the specific instance of m_h0. I am guessing the m_ball1 is also non static.
 

//m_ball1.SetIcon(m_h0); changed to use this pointer
ts->_this->m_ball1.SetIcon(ts->_this->m_h0);
 
Nitpicking: Why set the icon in a thread, rather than before calling thread in an initialize function? If you have to do it you should probably have a function
 
CCash3mfcDlg::SetIcon() {
m_ball1.SetIcon(m_h0);
}
 
and call it from your thread like this
ts->_this->SetIcon();
 
PS If you are just learning C++, you might want to start easier than multi threading OMG | :OMG: , but good luck, I admire your courage.
Smile | :)
GeneralRe: HELP PLEASEmemberwin32newb19 Mar '04 - 11:02 
Thanks for your help and encouragement on the project. I actually completed it. You were right about the static pass in the thread. here is what i did.
And as for the setting of the icon I did that for a specific reason. Maybe not the most suffient at the time but I am still learning. I have 3 icons on the screen to represent balls from 0 to 9 and i randomly generate a number sequence consisting of three numbers while the thread runs. and it displays that number sequence represented as balls. and I run it in the thread so it makes the balls look as if they are spinning.
 
here is a portion of the source pertaining to the thread.
http://rafb.net/paste/results/rx590089.html
 
Thanks again,
 
Win32newb
"Making windows programs worse than they already are"
GeneralRe: HELP PLEASEmemberjens winslow22 Mar '04 - 6:34 
Glad I could help Smile | :)
 
BTW, the link http://rafb.net/paste/results/rx590089.html does not seem to work Confused | :confused:
 
As for my nitpick about setting icons, please ignore that.
If you are trying to do sprite like animation (using icons because they can have transparency) running the "frames" from a worker thread seems like a good solution (IMO).
 
Jens
GeneralI thought you were supposed to pass handles, not pointers to objects into threads??? Not that that seems to work for me (HELP Please!)memberJens Winslow18 Jul '03 - 12:47 
It was my understanding that you should not pass pointers to CWnd objects like dialogs into threads, but pass the handle (using GetSafeHwnd), and then retrieve pointer in thread using CWnd* pWnd = CWnd::FromHandle(pParam).
 
But, I might be wrong - I am here becuse the examples showing the above does not seem to work for me when trying to give me access to a dialog from within a thread Confused | :confused:
(the returned pointer seems to point to some other uninitialized instance)
 
If anyone knows about this I would love to hear from you....please?
 
Example: CMyDlg:CDialog has member variable int m_iX = 5424992;
 
CMyDlg::OnBtnGo{) {
...
AfxBeginThread(MyProcc, this->AfxGetSafeHwnd())
...
}
 

UINT MyProcc(LPVOID pParam) {
CMyDlg* pDlg = (CMyDlg*)(CWnd::FromHandlePermanent((HWND)pParam));
TRACE1("X=%i", pDlg->m_iX;
}
 

results in 4258440 not 5424992 ?????
Incidentally, pDlg != this pointer in dlg,
but pParam = m_hWnd of dialog
 
Arrgghhhhh!!! Mad | :mad: Confused | :confused:
 
Any help on HOW I can access a member in MuDlg from a thread would be appreciated.
 
Jens
GeneralCorrection: AfxBeginThread(MyProcc, this-&gt;GetSafeHwnd()) NOT AfxBeginThread(MyProcc, this-&gt;AfxGetSafeHwnd())memberJens Winslow18 Jul '03 - 12:53 
Correction: AfxBeginThread(MyProcc, this->GetSafeHwnd()) NOT AfxBeginThread(MyProcc, this->AfxGetSafeHwnd())
 
Sorry about that

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web01 | 2.6.130516.1 | Last Updated 20 Jun 2002
Article Copyright 2002 by Enis
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid