Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. C / C++ / MFC
  4. Help with threads

Help with threads

Scheduled Pinned Locked Moved C / C++ / MFC
helplounge
35 Posts 7 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • J Joe Woodbury

    Good comment, but you may win an award for the most poorly formatted comment this year. :)

    P Offline
    P Offline
    pasztorpisti
    wrote on last edited by
    #10

    Well, formatting has never been a strength of mine... :-)

    1 Reply Last reply
    0
    • P pasztorpisti

      The less hassle free solution is sending a message from the worker thread to the ui thread by using SendMessage() or PostMessage() with one of your windows.

      D Offline
      D Offline
      David Crow
      wrote on last edited by
      #11

      pasztorpisti wrote:

      The less hassle free solution is sending a message from the worker thread to the ui thread by using SendMessage()...

      What happens when the primary (UI) thread is blocked and the worker thread sends it a message via SendMessage()?

      "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

      "Show me a community that obeys the Ten Commandments and I'll show you a less crowded prison system." - Anonymous

      P 1 Reply Last reply
      0
      • D David Crow

        pasztorpisti wrote:

        The less hassle free solution is sending a message from the worker thread to the ui thread by using SendMessage()...

        What happens when the primary (UI) thread is blocked and the worker thread sends it a message via SendMessage()?

        "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

        "Show me a community that obeys the Ten Commandments and I'll show you a less crowded prison system." - Anonymous

        P Offline
        P Offline
        pasztorpisti
        wrote on last edited by
        #12

        Then the worker thread is waiting until the message is processed on the gui thread. Exploiting this you can for example pop up a messagebox from the worker thread by sending a WM_APP+X message to the gui thread that processes WM_APP+X and "blocks" until the message box is closed. The worker thread continues running only after the message box is closed and the processing of WM_APP+X is finished on the gui thread. I quoted "blocks" because a MessageBox call doesn't really block the gui thread, it just blocks the processing of a single message an it runs an inner messageloop of its own so processing other messages from the queue of the gui thread goes on. For example your windows are still drawn (by WM_PAINT messages) while a messagebox is active. PS: The ui thread should never be blocked, that causes unresponsive UI. Often thats the reason for multithreading and not gaining performance. If your UI thread is blocked then your program is either buggy or poorly designed.

        D 1 Reply Last reply
        0
        • P pasztorpisti

          Then the worker thread is waiting until the message is processed on the gui thread. Exploiting this you can for example pop up a messagebox from the worker thread by sending a WM_APP+X message to the gui thread that processes WM_APP+X and "blocks" until the message box is closed. The worker thread continues running only after the message box is closed and the processing of WM_APP+X is finished on the gui thread. I quoted "blocks" because a MessageBox call doesn't really block the gui thread, it just blocks the processing of a single message an it runs an inner messageloop of its own so processing other messages from the queue of the gui thread goes on. For example your windows are still drawn (by WM_PAINT messages) while a messagebox is active. PS: The ui thread should never be blocked, that causes unresponsive UI. Often thats the reason for multithreading and not gaining performance. If your UI thread is blocked then your program is either buggy or poorly designed.

          D Offline
          D Offline
          David Crow
          wrote on last edited by
          #13

          pasztorpisti wrote:

          Then the worker thread is waiting until the message is processed on the gui thread.

          I'm not talking about the primary thread being busy for a few nanoseconds. I'm talking about deadlock. For example, the secondary thread sends a "add item to the control" message (e.g., LB_ADDSTRING) to the primary thread, which is blocked waiting on the secondary thread to complete. Now the secondary thread cannot complete because it is no longer running (waiting on SendMessage() to return). This is the primary reason why SendMessage() should rarely, if ever, be used to communicate between primary and secondary threads.

          "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

          "Show me a community that obeys the Ten Commandments and I'll show you a less crowded prison system." - Anonymous

          P C 2 Replies Last reply
          0
          • D David Crow

            pasztorpisti wrote:

            Then the worker thread is waiting until the message is processed on the gui thread.

            I'm not talking about the primary thread being busy for a few nanoseconds. I'm talking about deadlock. For example, the secondary thread sends a "add item to the control" message (e.g., LB_ADDSTRING) to the primary thread, which is blocked waiting on the secondary thread to complete. Now the secondary thread cannot complete because it is no longer running (waiting on SendMessage() to return). This is the primary reason why SendMessage() should rarely, if ever, be used to communicate between primary and secondary threads.

            "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

            "Show me a community that obeys the Ten Commandments and I'll show you a less crowded prison system." - Anonymous

            P Offline
            P Offline
            pasztorpisti
            wrote on last edited by
            #14

            The gui thread should never block, as a consequence it should never wait for the worker thread to complete. When the worker thread completes it can send/post a message to the gui thread to signal. Why would you want a blocking-wait on the gui thread???

            A 1 Reply Last reply
            0
            • D David Crow

              pasztorpisti wrote:

              Then the worker thread is waiting until the message is processed on the gui thread.

              I'm not talking about the primary thread being busy for a few nanoseconds. I'm talking about deadlock. For example, the secondary thread sends a "add item to the control" message (e.g., LB_ADDSTRING) to the primary thread, which is blocked waiting on the secondary thread to complete. Now the secondary thread cannot complete because it is no longer running (waiting on SendMessage() to return). This is the primary reason why SendMessage() should rarely, if ever, be used to communicate between primary and secondary threads.

              "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

              "Show me a community that obeys the Ten Commandments and I'll show you a less crowded prison system." - Anonymous

              C Offline
              C Offline
              Chuck OToole
              wrote on last edited by
              #15

              DavidCrow wrote:

              For example, the secondary thread sends a "add item to the control" message (e.g., LB_ADDSTRING) to the primary thread

              This is the scenario that's confused me from time to time. It is really legal for a thread to do a SendMessage() to a control (the target of the LB_ADDSTRING) that is owned by another thread? I thought that Windows checked "thread ownership" of the control and returned an error on the SendMessage(). If the "primary thread" is, as is implied in your reply, the UI thread, then the "secondary thread" should not be allowed access to the control. I've always used "PostMessage()" and used "user defined messages" to have secondary threads pass messages / commands to the primary thread for action. Since "PostMessage()" is just a queueing action, there is no deadlock (although you might not get the immediate feedback of a screen update). Does anyone have the definitive answer on "SendMessage and Control Owner Thread" question?

              A 1 Reply Last reply
              0
              • P pasztorpisti

                The less hassle free solution is sending a message from the worker thread to the ui thread by using SendMessage() or PostMessage() with one of your windows.

                A Offline
                A Offline
                AndrewG1231
                wrote on last edited by
                #16

                Ok, instead of modifying my original question I will continue the thread since it has been really helpful. So, my program uses the following code to create a new thread.

                m_Thread = AfxBeginThread(Acq_Data,this,THREAD_PRIORITY_HIGHEST);

                This thread is told to look at the current class and the controlling function is Acq_Data. In Acq_Data there is the following code.

                while(dlg->m_Continue && ! dlg->m_inst->m_Flags.Halt)
                {
                dlg->m_inst->ADCdbInquire(dlg->m_halfdata,hdlg,MSG_DRAW_SPECTRUM);
                }

                The ADCdbInquire()function contains a call to PostMessage()

                bool CPXI::ADCdbInquire(short *halfbuffer, HWND hwnd ,int Message)
                {
                short iStatus, iHalfReady, iDAQstopped = 0;
                unsigned long ulPtsTfr=1500; // number of points transferred

                // Are you ready?
                iStatus = DAQ\_DB\_HalfReady(m\_6052\_Device, &iHalfReady,
                     &iDAQstopped);
                
                if ((iHalfReady == 1) && (iDAQstopped == 0))
                {
                    iStatus = DAQ\_DB\_Transfer(m\_6052\_Device, halfbuffer,
                    &ulPtsTfr, &iDAQstopped);
                
                    NIDAQErrorHandler(iStatus, "DAQ\_DB\_Transfer",m\_SuppressErrors);
                
                    if(Message != -1)
                        PostMessage(hwnd,WM\_COMMAND,Message,NULL);
                
                    return true;
                }
                return false;
                

                }

                and is sending a custom message defined in the header file. #define MSG_DRAW_SPECTRUM (WM_APP + 5) This custom messages refers to member function OnDrawSpectrum() where the following code exists to update the window.

                void CDlg_SpectrumAnalyzer::OnDrawSpectrum()
                {

                int starti,finishi;
                starti = m\_datacount \* m\_BuffSize / 2;
                finishi = (m\_datacount + 1)\* m\_BuffSize / 2;
                
                if(finishi > m\_AcqNPts)
                    finishi = m\_AcqNPts;
                
                int j = 0;
                for(int i = starti; i < finishi; i++)
                {
                    m\_fftdata\[i\].re = m\_halfdata\[j++\];
                    m\_fftdata\[i\].im = 0.;
                }
                
                
                
                m\_datacount++;
                
                // if we are done collecting draw the graph
                if((m\_datacount == m\_NBuffs))
                {
                
                    OnSpectrumStart();
                    float freq = 0;
                    float stepsize = ((float)(m\_MaxFreq)) / ((float)(m\_AcqNPts-1)/2.0);
                    m\_datacount = 0;
                
                    m\_Graph->ClearGraph(m\_graphNum,false);
                
                    // do fft
                    fftw\_one(m\_the\_plan, m\_fftdata, NULL);
                
                    //m\_AcqNPts should be 2^n therefore /2 should be integer
                    for(int i = m\_AcqNPts-1; i >= m\_AcqNPts/2;
                
                D 1 Reply Last reply
                0
                • P pasztorpisti

                  The less hassle free solution is sending a message from the worker thread to the ui thread by using SendMessage() or PostMessage() with one of your windows.

                  A Offline
                  A Offline
                  Albert Holguin
                  wrote on last edited by
                  #17

                  Actually, SendMessage is synchronous... so if it's threaded, it really should be a PostMessage, otherwise you'll tie up the worker thread waiting on the GUI update.

                  1 Reply Last reply
                  0
                  • J Joe Woodbury

                    Good comment, but you may win an award for the most poorly formatted comment this year. :)

                    A Offline
                    A Offline
                    Albert Holguin
                    wrote on last edited by
                    #18

                    Yeah that was pretty painful :)

                    1 Reply Last reply
                    0
                    • C Chuck OToole

                      DavidCrow wrote:

                      For example, the secondary thread sends a "add item to the control" message (e.g., LB_ADDSTRING) to the primary thread

                      This is the scenario that's confused me from time to time. It is really legal for a thread to do a SendMessage() to a control (the target of the LB_ADDSTRING) that is owned by another thread? I thought that Windows checked "thread ownership" of the control and returned an error on the SendMessage(). If the "primary thread" is, as is implied in your reply, the UI thread, then the "secondary thread" should not be allowed access to the control. I've always used "PostMessage()" and used "user defined messages" to have secondary threads pass messages / commands to the primary thread for action. Since "PostMessage()" is just a queueing action, there is no deadlock (although you might not get the immediate feedback of a screen update). Does anyone have the definitive answer on "SendMessage and Control Owner Thread" question?

                      A Offline
                      A Offline
                      Albert Holguin
                      wrote on last edited by
                      #19

                      That's a good question... I do believe the framework allows you to do it though... although now that you're questioning it, you're making me question whether I remember that correctly.

                      C 1 Reply Last reply
                      0
                      • P pasztorpisti

                        The gui thread should never block, as a consequence it should never wait for the worker thread to complete. When the worker thread completes it can send/post a message to the gui thread to signal. Why would you want a blocking-wait on the gui thread???

                        A Offline
                        A Offline
                        Albert Holguin
                        wrote on last edited by
                        #20

                        SendMessage() is a blocking call... that's what he was pointing out.

                        1 Reply Last reply
                        0
                        • A AndrewG1231

                          Ok, instead of modifying my original question I will continue the thread since it has been really helpful. So, my program uses the following code to create a new thread.

                          m_Thread = AfxBeginThread(Acq_Data,this,THREAD_PRIORITY_HIGHEST);

                          This thread is told to look at the current class and the controlling function is Acq_Data. In Acq_Data there is the following code.

                          while(dlg->m_Continue && ! dlg->m_inst->m_Flags.Halt)
                          {
                          dlg->m_inst->ADCdbInquire(dlg->m_halfdata,hdlg,MSG_DRAW_SPECTRUM);
                          }

                          The ADCdbInquire()function contains a call to PostMessage()

                          bool CPXI::ADCdbInquire(short *halfbuffer, HWND hwnd ,int Message)
                          {
                          short iStatus, iHalfReady, iDAQstopped = 0;
                          unsigned long ulPtsTfr=1500; // number of points transferred

                          // Are you ready?
                          iStatus = DAQ\_DB\_HalfReady(m\_6052\_Device, &iHalfReady,
                               &iDAQstopped);
                          
                          if ((iHalfReady == 1) && (iDAQstopped == 0))
                          {
                              iStatus = DAQ\_DB\_Transfer(m\_6052\_Device, halfbuffer,
                              &ulPtsTfr, &iDAQstopped);
                          
                              NIDAQErrorHandler(iStatus, "DAQ\_DB\_Transfer",m\_SuppressErrors);
                          
                              if(Message != -1)
                                  PostMessage(hwnd,WM\_COMMAND,Message,NULL);
                          
                              return true;
                          }
                          return false;
                          

                          }

                          and is sending a custom message defined in the header file. #define MSG_DRAW_SPECTRUM (WM_APP + 5) This custom messages refers to member function OnDrawSpectrum() where the following code exists to update the window.

                          void CDlg_SpectrumAnalyzer::OnDrawSpectrum()
                          {

                          int starti,finishi;
                          starti = m\_datacount \* m\_BuffSize / 2;
                          finishi = (m\_datacount + 1)\* m\_BuffSize / 2;
                          
                          if(finishi > m\_AcqNPts)
                              finishi = m\_AcqNPts;
                          
                          int j = 0;
                          for(int i = starti; i < finishi; i++)
                          {
                              m\_fftdata\[i\].re = m\_halfdata\[j++\];
                              m\_fftdata\[i\].im = 0.;
                          }
                          
                          
                          
                          m\_datacount++;
                          
                          // if we are done collecting draw the graph
                          if((m\_datacount == m\_NBuffs))
                          {
                          
                              OnSpectrumStart();
                              float freq = 0;
                              float stepsize = ((float)(m\_MaxFreq)) / ((float)(m\_AcqNPts-1)/2.0);
                              m\_datacount = 0;
                          
                              m\_Graph->ClearGraph(m\_graphNum,false);
                          
                              // do fft
                              fftw\_one(m\_the\_plan, m\_fftdata, NULL);
                          
                              //m\_AcqNPts should be 2^n therefore /2 should be integer
                              for(int i = m\_AcqNPts-1; i >= m\_AcqNPts/2;
                          
                          D Offline
                          D Offline
                          David Crow
                          wrote on last edited by
                          #21

                          AndrewG1231 wrote:

                          So, my question...in order to get this sequence to run several times, say 5 times, and update the window how would I use PostMessage()? Or if I have misunderstood something please let me know.

                          See here for more.

                          "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

                          "Show me a community that obeys the Ten Commandments and I'll show you a less crowded prison system." - Anonymous

                          A 1 Reply Last reply
                          0
                          • A Albert Holguin

                            That's a good question... I do believe the framework allows you to do it though... although now that you're questioning it, you're making me question whether I remember that correctly.

                            C Offline
                            C Offline
                            Chuck OToole
                            wrote on last edited by
                            #22

                            You know, some days I don't remember where my head is. Of course you can do it and, in fact, I do it all the time in certain apps. For example, if I have a "DO IT!" button, that usually creates a worker thread that does some stuff and updates a "log view" edit control in the main dialog. The GUI thread continues on and watches for the user clicking on "STOP DOING IT!". Meanwhile, the worker thread does a

                            TheDialog->m_editcontrol.SetText(logbuffer);

                            or something equivalent to update the subclassed edit window. Works just fine. I guess I forget this because the "SendMessage()" is buried in the SetText() function and not something I explicitly do but it is still "SendMessage()" from a thread that did not "own" or "create" the control. Oh well, must be getting old.

                            A 1 Reply Last reply
                            0
                            • C Chuck OToole

                              You know, some days I don't remember where my head is. Of course you can do it and, in fact, I do it all the time in certain apps. For example, if I have a "DO IT!" button, that usually creates a worker thread that does some stuff and updates a "log view" edit control in the main dialog. The GUI thread continues on and watches for the user clicking on "STOP DOING IT!". Meanwhile, the worker thread does a

                              TheDialog->m_editcontrol.SetText(logbuffer);

                              or something equivalent to update the subclassed edit window. Works just fine. I guess I forget this because the "SendMessage()" is buried in the SetText() function and not something I explicitly do but it is still "SendMessage()" from a thread that did not "own" or "create" the control. Oh well, must be getting old.

                              A Offline
                              A Offline
                              Albert Holguin
                              wrote on last edited by
                              #23

                              Chuck O'Toole wrote:

                              Oh well, must be getting old.

                              Happens... Yeah, as a rule of thumb though, I like to tell people to PostMessage() when doing things between threads (since they're supposed to be independent anyway). As you probably know, the synchronicity of SendMessage() has the potential for deadlocks so it should only be used when you truly need it.

                              1 Reply Last reply
                              0
                              • D David Crow

                                AndrewG1231 wrote:

                                So, my question...in order to get this sequence to run several times, say 5 times, and update the window how would I use PostMessage()? Or if I have misunderstood something please let me know.

                                See here for more.

                                "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

                                "Show me a community that obeys the Ten Commandments and I'll show you a less crowded prison system." - Anonymous

                                A Offline
                                A Offline
                                AndrewG1231
                                wrote on last edited by
                                #24

                                Thanks for the link to the article and I have tried to implement the PostMessage() in my code. However, I am still having problems trying to get it to execute more than once and update the window (looping the code is not working). After reading your suggested article, I am still not sure how to do this correctly, can you help? My code is as follows.

                                void CDlg_SpectrumAnalyzer::OnBtnClickedRun()
                                {
                                PostMessage(WM_COMMAND,IDC_SPECTRUM_START,0);
                                }

                                Yes, this is a "Run" button that sends the message and it executes correctly if called only a single time.

                                D 1 Reply Last reply
                                0
                                • A AndrewG1231

                                  Thanks for the link to the article and I have tried to implement the PostMessage() in my code. However, I am still having problems trying to get it to execute more than once and update the window (looping the code is not working). After reading your suggested article, I am still not sure how to do this correctly, can you help? My code is as follows.

                                  void CDlg_SpectrumAnalyzer::OnBtnClickedRun()
                                  {
                                  PostMessage(WM_COMMAND,IDC_SPECTRUM_START,0);
                                  }

                                  Yes, this is a "Run" button that sends the message and it executes correctly if called only a single time.

                                  D Offline
                                  D Offline
                                  David Crow
                                  wrote on last edited by
                                  #25

                                  AndrewG1231 wrote:

                                  ...it executes correctly if called only a single time.

                                  What happens when the handler is called a second time?

                                  "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

                                  "Show me a community that obeys the Ten Commandments and I'll show you a less crowded prison system." - Anonymous

                                  A 1 Reply Last reply
                                  0
                                  • D David Crow

                                    AndrewG1231 wrote:

                                    ...it executes correctly if called only a single time.

                                    What happens when the handler is called a second time?

                                    "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

                                    "Show me a community that obeys the Ten Commandments and I'll show you a less crowded prison system." - Anonymous

                                    A Offline
                                    A Offline
                                    AndrewG1231
                                    wrote on last edited by
                                    #26

                                    When it is called the second time I encounter some code for checking the state of the instrument my program is controlling. You can see the whole block of code this belongs to in the first post of this thread.

                                    if(!m_inst->StartOperation())
                                    {
                                    MessageBox("The Instrument is Currently in use by another function");
                                    return;
                                    }

                                    I thought this indicated that the previous thread wasn't terminating before the message posted again and I tried to use Sleep() to delay the call, but this did not work. I encountered the same situation or the window did not update. I also tried to use the WaitForSingleObject(), but this failed as well.

                                    D 1 Reply Last reply
                                    0
                                    • A AndrewG1231

                                      When it is called the second time I encounter some code for checking the state of the instrument my program is controlling. You can see the whole block of code this belongs to in the first post of this thread.

                                      if(!m_inst->StartOperation())
                                      {
                                      MessageBox("The Instrument is Currently in use by another function");
                                      return;
                                      }

                                      I thought this indicated that the previous thread wasn't terminating before the message posted again and I tried to use Sleep() to delay the call, but this did not work. I encountered the same situation or the window did not update. I also tried to use the WaitForSingleObject(), but this failed as well.

                                      D Offline
                                      D Offline
                                      David Crow
                                      wrote on last edited by
                                      #27

                                      Look this over. It's from memory and completly untested so there may be a few small details left out, but it should give you good idea of how primary and secondary threads communicate.

                                      BEGIN_MESSAGE_MAP(CMyDialog, CDiaog)
                                      ON_BN_CLICKED(IDC_BUTTON, OnClick)
                                      END_MESSAGE_MAP()

                                      void CMyDialog::Acq_Data( void )
                                      {
                                      while (1)
                                      {
                                      // if a STOP event has been signaled [m_pEventStopRequested.SetEvent()]
                                      if (WaitForSingleObject(m_pEventStopRequested->m_hObject, 0U) == WAIT_OBJECT_0)
                                      {
                                      // let OnClick() know that the secondary thread is not running
                                      m_pEventThreadDone->SetEvent();

                                              return;
                                          }
                                          else
                                              ADCdbInquire(...); // this functon can post messages back to the primary thread
                                      }
                                      

                                      }

                                      /* static */ UINT CMyDialog::Acq_Data( LPVOID lpVoid )
                                      {
                                      CMyDialog *pDlg = (CMyDialog *) lpVoid;

                                      pDlg->Acq\_Data();
                                      
                                      // once here, the secondary thread is done so post a message
                                      // back to the primary thread to tell it to enable the button
                                      
                                      return 0;
                                      

                                      }

                                      // put these in CMyDialog
                                      CWinThread *m_pThread = NULL;
                                      CEvent *m_pEventStopRequested = new CEvent(FALSE, TRUE); // stop requested (initially no)?
                                      CEvent *m_pEventThreadDone = new CEvent(TRUE, TRUE); // thread done (initially yes)?

                                      void CMyDialog::OnClick()
                                      {
                                      // if the secondary thread is not running
                                      if (WaitForSingleObject(m_pEventThreadDone->m_hObject, 0U) == WAIT_OBJECT_0)
                                      {
                                      // at this point, you could disable the button that
                                      // started this so that it could not be clicked again

                                          // set the STOP and DONE events to nonsignaled (haven't happened yet)
                                          m\_pEventStopRequested->ResetEvent();
                                          m\_pEventThreadDone->ResetEvent();
                                      
                                          // start the secondary thread
                                          m\_pThread = AfxBeginThread(Acq\_Data, this, THREAD\_PRIORITY\_HIGHEST);
                                      }
                                      

                                      }

                                      "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

                                      "Show me a community that obeys the Ten Commandments and I'll show you a less crowded prison system." - Anonymous

                                      A 1 Reply Last reply
                                      0
                                      • D David Crow

                                        Look this over. It's from memory and completly untested so there may be a few small details left out, but it should give you good idea of how primary and secondary threads communicate.

                                        BEGIN_MESSAGE_MAP(CMyDialog, CDiaog)
                                        ON_BN_CLICKED(IDC_BUTTON, OnClick)
                                        END_MESSAGE_MAP()

                                        void CMyDialog::Acq_Data( void )
                                        {
                                        while (1)
                                        {
                                        // if a STOP event has been signaled [m_pEventStopRequested.SetEvent()]
                                        if (WaitForSingleObject(m_pEventStopRequested->m_hObject, 0U) == WAIT_OBJECT_0)
                                        {
                                        // let OnClick() know that the secondary thread is not running
                                        m_pEventThreadDone->SetEvent();

                                                return;
                                            }
                                            else
                                                ADCdbInquire(...); // this functon can post messages back to the primary thread
                                        }
                                        

                                        }

                                        /* static */ UINT CMyDialog::Acq_Data( LPVOID lpVoid )
                                        {
                                        CMyDialog *pDlg = (CMyDialog *) lpVoid;

                                        pDlg->Acq\_Data();
                                        
                                        // once here, the secondary thread is done so post a message
                                        // back to the primary thread to tell it to enable the button
                                        
                                        return 0;
                                        

                                        }

                                        // put these in CMyDialog
                                        CWinThread *m_pThread = NULL;
                                        CEvent *m_pEventStopRequested = new CEvent(FALSE, TRUE); // stop requested (initially no)?
                                        CEvent *m_pEventThreadDone = new CEvent(TRUE, TRUE); // thread done (initially yes)?

                                        void CMyDialog::OnClick()
                                        {
                                        // if the secondary thread is not running
                                        if (WaitForSingleObject(m_pEventThreadDone->m_hObject, 0U) == WAIT_OBJECT_0)
                                        {
                                        // at this point, you could disable the button that
                                        // started this so that it could not be clicked again

                                            // set the STOP and DONE events to nonsignaled (haven't happened yet)
                                            m\_pEventStopRequested->ResetEvent();
                                            m\_pEventThreadDone->ResetEvent();
                                        
                                            // start the secondary thread
                                            m\_pThread = AfxBeginThread(Acq\_Data, this, THREAD\_PRIORITY\_HIGHEST);
                                        }
                                        

                                        }

                                        "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

                                        "Show me a community that obeys the Ten Commandments and I'll show you a less crowded prison system." - Anonymous

                                        A Offline
                                        A Offline
                                        AndrewG1231
                                        wrote on last edited by
                                        #28

                                        Thanks for the suggestions! However, this piece of code is causing me to get the error, "A nonstatic member reference must be relative to a specific object". I tried to use this-> before m_pEventStopRequested->m_hObject but it did not solve the problem. I have the declaration for the CEvent in the constructor, but I am not sure to what object it is referring.

                                        if (WaitForSingleObject(m_pEventStopRequested->m_hObject, 0U) == WAIT_OBJECT_0)
                                        {
                                        // let OnClick() know that the secondary thread is not running
                                        m_pEventThreadDone.SetEvent();
                                        return;
                                        }

                                        Would you happen to know what object it is referring to?

                                        D 1 Reply Last reply
                                        0
                                        • A AndrewG1231

                                          Thanks for the suggestions! However, this piece of code is causing me to get the error, "A nonstatic member reference must be relative to a specific object". I tried to use this-> before m_pEventStopRequested->m_hObject but it did not solve the problem. I have the declaration for the CEvent in the constructor, but I am not sure to what object it is referring.

                                          if (WaitForSingleObject(m_pEventStopRequested->m_hObject, 0U) == WAIT_OBJECT_0)
                                          {
                                          // let OnClick() know that the secondary thread is not running
                                          m_pEventThreadDone.SetEvent();
                                          return;
                                          }

                                          Would you happen to know what object it is referring to?

                                          D Offline
                                          D Offline
                                          David Crow
                                          wrote on last edited by
                                          #29

                                          AndrewG1231 wrote:

                                          However, this piece of code is causing me to get the error, "A nonstatic member reference must be relative to a specific object".

                                          What is the exact error number?

                                          AndrewG1231 wrote:

                                          m_pEventThreadDone.SetEvent();

                                          Should be:

                                          m_pEventThreadDone->SetEvent();

                                          That, and adding a return value, is all I had to do to get the code to compile.

                                          "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

                                          "Show me a community that obeys the Ten Commandments and I'll show you a less crowded prison system." - Anonymous

                                          A 1 Reply Last reply
                                          0
                                          Reply
                                          • Reply as topic
                                          Log in to reply
                                          • Oldest to Newest
                                          • Newest to Oldest
                                          • Most Votes


                                          • Login

                                          • Don't have an account? Register

                                          • Login or register to search.
                                          • First post
                                            Last post
                                          0
                                          • Categories
                                          • Recent
                                          • Tags
                                          • Popular
                                          • World
                                          • Users
                                          • Groups