CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Page 1 of 2 12 LastLast
Results 1 to 15 of 22

Thread: threading

  1. #1
    Join Date
    Jan 2003
    Posts
    615

    threading

    Hello,

    I've created an mfc application which at the moment listen to a specific port using csocket and output the data into a text file. This process is run in a separate thread (a worker thread I belive). The program works fine.

    To upgrade the program I thought about adding a text field with a cstring object attached to it. My question is then, how can I update the textfield with the data that my listen-thread receive ? Can I post\send the data or a pointer from one thread to another ? What about synchronising ?

    Links to related articles or tutorials would be much appreciated.

    Cheers

  2. #2
    Join Date
    May 2000
    Location
    KY, USA
    Posts
    18,652
    Take a look at the following FAQ...

  3. #3
    Join Date
    Feb 2002
    Posts
    5,757
    One solution is messages.

    Kuphryn

  4. #4
    Join Date
    Jan 2003
    Posts
    615
    The below code compiles and links ok but I get an 'Unhandled exception at 0x00.... access violation" at the :ostmessage line.
    Code:
    struct threadData
    {
    	Driver *d;
    	HWND *hwnd;
    };
    
    UINT StartThread( LPVOID pParam )
    {
    	threadData * structData = (threadData*) pParam;
    	Driver *obj = structData->d;
    	HWND *hwnd  = structData->hwnd;
    	if (obj == 0)
    		return -1;
    
    	int status = obj->start(hwnd);
    	return 0;
    }
    
    LRESULT CReceiverDlg::OnUpdateControl(WPARAM wParam, LPARAM lParam)
    {
      // TODO - add code
      return 0;
    }
    
    BEGIN_MESSAGE_MAP(CReceiverDlg, CDialog)
    	ON_WM_PAINT()
    	ON_WM_QUERYDRAGICON()
    	//}}AFX_MSG_MAP
    	ON_MESSAGE(WM_UPDATE_CONTROL, OnUpdateControl)
    END_MESSAGE_MAP()
    
    BOOL CReceiverDlg::OnInitDialog()
    {
    	// more code...
    	Driver *drv = new Driver();
    	threadData *obj = new threadData();
    	obj->d = drv;
    	obj->hwnd = (HWND*)GetSafeHwnd(); 
    	AfxBeginThread(StartThread, (LPVOID) drv);
    
    	return TRUE;  
    }
    
    int Driver::start(HWND * hwnd)
    {
    	CSocket sock;
    	char buf[1024];
    	CString addr;
    	UINT port;
    	if (sock.Create(5000, SOCK_DGRAM, "10.0.0.10") == 0)
    		return -1;
    
    	while(1)
    	{
    		int received_bytes = sock.ReceiveFrom((void*) buf, 1024, addr, port);
    		if (received_bytes == SOCKET_ERROR)
    		{
    			out << "Recevefrom failed" << endl;
    			return -1;
    		}
    	         ::PostMessage(*hwnd, WM_UPDATE_CONTROL, 0, 0);
    	}
    	sock.Close();
    	return 0;
    }
    How can I post the buf data back to the primary thread ?

  5. #5
    Join Date
    May 2000
    Location
    KY, USA
    Posts
    18,652
    Your problem is the following line
    Code:
    obj->hwnd = (HWND*)GetSafeHwnd();
    'GetSafeHwnd()' returns a 'HWND' and not a pointer. You treat the returned handle as a pointer to a handle (by casting it). While dereferencing it in the thread function you of course call for trouble...

    Change your structure to accept a HWND...
    Code:
    struct threadData
    {
      Driver *d;
      HWND hwnd;
    };
    Then assign it accordingly...
    Code:
    obj->hwnd = GetSafeHwnd();
    The thread function needs to delete the passed data structure before it terminates otherwise you will have memory leaks...
    Code:
    UINT StartThread( LPVOID pParam )
    {
      threadData * structData = (threadData*) pParam;
      Driver *obj = structData->d;
      HWND hwnd  = structData->hwnd;
      if (obj == 0)
        return -1;
    
      int status = obj->start(hwnd);
    
      // Delete passed data
      delete structData;
    
      return 0;
    }
    Finally your 'start()' function...
    Code:
    int Driver::start(HWND hwnd)
    {
      CSocket sock;
      char buf&#091;1024&#093;;
      CString addr;
      UINT port;
    
      if (sock.Create(5000, SOCK_DGRAM, "10.0.0.10") == 0)
        return -1;
    
      while(1)
      {
        int received_bytes = sock.ReceiveFrom((void*) buf, 1024, addr, port);
    
        if (received_bytes == SOCKET_ERROR)
        {
          out << "Recevefrom failed" << endl;
          return -1;
        }
    
        ::PostMessage(hwnd, WM_UPDATE_CONTROL, 0, 0);
      }
    
      sock.Close();
      return 0;
    }
    Last edited by Andreas Masur; January 24th, 2004 at 05:38 PM.

  6. #6
    Join Date
    Jan 2004
    Posts
    20
    Originally posted by Andreas Masur

    The thread function needs to delete the passed data structure before it terminates otherwise you will have memory leaks...
    that´s a bad policy - better leave the memory management for the threadData completely to the dialog object:

    • add a threadData member
    • initialize it inside the onInitDialog() function
    • pass its address to the thread (no new/delete needed)


    otherwise if you happen to pass the same pointer to more than one thread, your solution leads to multiple deletes.

    next, to pass the data back to the dialog, you need a common buffer and a synchronization object to serialize access to it (say, 2 more members for the threadData struct, a char[] and a mutex, and have them passed forward to the Driver::start() function as well)

  7. #7
    Join Date
    May 2000
    Location
    KY, USA
    Posts
    18,652
    Originally posted by abc_coder
    that´s a bad policy - better leave the memory management for the threadData completely to the dialog object:

    • add a threadData member
    • initialize it inside the onInitDialog() function
    • pass its address to the thread (no new/delete needed)


    otherwise if you happen to pass the same pointer to more than one thread, your solution leads to multiple deletes.
    Well...I do not want to start a big discussion about how to do these things right. Nevertheless your solution lacks from some of the mentioned points as well and requires more handling then you have described.

    Since the thread data are a member of your class, you need to make sure that the thread will be terminated before your class will be destroyed. Otherwise your thread will deal with a dangling pointer.

    Another point is the number of threads. As long as each thread gets the same data you can simply use one structure. However, as soon as the data needs to vary for each thread you will simply fill up your class with n member variables.

    Originally posted by abc_coder
    next, to pass the data back to the dialog, you need a common buffer and a synchronization object to serialize access to it (say, 2 more members for the threadData struct, a char[] and a mutex, and have them passed forward to the Driver::start() function as well)
    This might be a different approach while dealing with one thread, nevertheless, Windows is an event-driven operating system...so, why not make use of it?

    Furthermore, this approach is not practible while dealing with several threads...first of all the processing time would decrease since every thread has to wait until the previous result would have been processed, and adding several kernel objects adds another overhead which is not necessary...

  8. #8
    Join Date
    Jan 2003
    Posts
    615
    Andreas Masur, thanks for your reply. I've made the updates you adviced. The code now both compiles\links and runs just fine without any error messages.

    The problem however is that OnUpdateControl() doesnt seem to be executed when :ostmessage is executed.

    Just for testing purpose my OnUpdateControl lools like this :
    Code:
    LRESULT CReceiverDlg::OnUpdateControl(WPARAM wParam, LPARAM lParam)
    {
      GetDlgItem(IDC_EDIT1)->SetWindowText("OnUpdateControl");
      return 0;
    }
    Let me know if you need more information.

  9. #9
    Join Date
    May 2000
    Location
    KY, USA
    Posts
    18,652
    Did you define all necessary entries in the message map? Maybe you can post the definition of the message and the mapping of the message to the function in the message map.

    Other than that, I do not see any reason why it should not work...

  10. #10
    Join Date
    Jan 2003
    Posts
    615
    Thanks for your prompt reply.

    Code:
    #define WM_UPDATE_CONTROL    WM_USER + 0x10
    
    BEGIN_MESSAGE_MAP(CReceiverDlg, CDialog)
    	ON_WM_PAINT()
    	ON_WM_QUERYDRAGICON()
    	//}}AFX_MSG_MAP
    	ON_MESSAGE(WM_UPDATE_CONTROL, OnUpdateControl)
    	ON_BN_CLICKED(IDOK, OnBnClickedOk)
    END_MESSAGE_MAP()
    Do you need anymore code ?

  11. #11
    Join Date
    May 2000
    Location
    KY, USA
    Posts
    18,652
    Well...looks okay except that you should change 'WM_USER' to 'WM_APP' (it was from the FAQ, however, I have changed the FAQ accordingly...).

    Can you probably post your project here (without the debug and release directories)?

  12. #12
    Join Date
    Jan 2003
    Posts
    615
    Here is my project files.

    Thanks for your help man.
    Attached Files Attached Files

  13. #13
    Join Date
    May 2000
    Location
    KY, USA
    Posts
    18,652
    After getting through some compiler errors and warnings (you did not send the 'res' directory), it is running okay with the following changes:
    • Remove '#define WM_UPDATE_CONTROL WM_USER + 0x10' from Driver.h
    • Change #include "fstream.h" to #include"fstream" in 'Driver.cpp' and put it a the top
    • Add #include "iostream" in 'Driver.cpp' and put it a the top as well
    • Add #include "ReceiverDlg.h" in 'Driver.cpp'
    • Change 'ofstream out("file.txt");' to 'std::ofstream out("file.txt");' in Driver.cpp
    • Change 'endl' to 'std::endl' in Driver.cpp
    • Add #include "resource.h" in 'ReceiverDlg.h'
    • Change in to the following in 'OnInitDialog()' of 'ReceiverDlg.cpp':
      Code:
      threadData *obj = new threadData();
        
      obj->d = new Driver();
      obj->hwnd = GetSafeHwnd(); 
        
      AfxBeginThread(StartThread, (LPVOID) obj);
    • Change the function 'StartThread' in 'ReceiverDlg.cpp' as follows:
      Code:
      UINT StartThread(LPVOID pParam)
      {
        threadData * structData = (threadData*) pParam;
        Driver *obj = structData->d;
        HWND hwnd  = structData->hwnd;
        if (obj == 0)
          return -1;
      
        int status = obj->start(hwnd);
        delete structData->d;
        delete structData;
        return 0;
      }

  14. #14
    Join Date
    Jan 2003
    Posts
    615
    Andreas Masur, thank you sir.

    Your help is much appreciated

  15. #15
    Join Date
    May 2000
    Location
    KY, USA
    Posts
    18,652
    Originally posted by laasunde
    Andreas Masur, thank you sir.

    Your help is much appreciated
    You are welcome...

Page 1 of 2 12 LastLast

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured