How can i implement a message pump with winforms ?

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • nicolas.hilaire@motorola.com

    How can i implement a message pump with winforms ?

    Hi all,

    i'm doing a quite long treatment in a function, and i'm showing the
    progress of the treatment with a progressbar. The code is something
    like this :

    for each(entry in entries) // about 100 entries
    {
    TreatmentForOne Or2Secs();
    this->progressBar1->PerformStep( );
    }


    during the debug, the debugger tells me that :

    Managed Debugging Assistant 'ContextSwitchD eadlock' has detected a
    problem in 'd:\test\NetSen dDotNet\debug\N etSendDotNet.ex e'.
    Additional Information: The CLR has been unable to transition from COM
    context 0x189558 to COM context 0x189408 for 60 seconds. The thread
    that owns the destination context/apartment is most likely either doing
    a non pumping wait or processing a very long running operation without
    pumping Windows messages. This situation generally has a negative
    performance impact and may even lead to the application becoming non
    responsive or memory usage accumulating continually over time. To avoid
    this problem, all single threaded apartment (STA) threads should use
    pumping wait primitives (such as CoWaitForMultip leHandles) and
    routinely pump messages during long running operations.


    Specially :
    To avoid this problem, all single threaded apartment (STA) threads
    should use pumping wait primitives (such as CoWaitForMultip leHandles)
    and routinely pump messages during long running operations.

    So, how can i pumping messages ? or, should i use a thread (and how ?)


    Thanks for your help


    Nicolas H.

  • Bruno van Dooren

    #2
    Re: How can i implement a message pump with winforms ?

    >Specially :[color=blue]
    >To avoid this problem, all single threaded apartment (STA) threads
    >should use pumping wait primitives (such as CoWaitForMultip leHandles)
    >and routinely pump messages during long running operations.[/color]
    [color=blue]
    >So, how can i pumping messages ? or, should i use a thread (and how ?)[/color]

    A more elegant solution perhaps is to use a timer.
    on each elapsed timer event, process one work item. this will give your
    application the chance to perform aditional message processing in between
    your own processing.

    this also means that your overall processing will take longer, since you are
    not continuously processing your own stuff.
    using a separate thread will give you a bit better performance,but requires
    more coding.

    pumping messages inside a message handler is something i've never tried in
    ..NET, so I don't know if it is possible or not.

    kind regards,
    Bruno.
    bruno_nos_pam_v an_dooren@hotma il.com
    Remove only "_nos_pam"

    Comment

    • Willy Denoyette [MVP]

      #3
      Re: How can i implement a message pump with winforms ?

      Call routinely CurrentThread->Join(0), this implicitely calls
      CoWaitForMultip leHandles and returns.

      Willy.


      <nicolas.hilair e@motorola.com> wrote in message
      news:1139825663 .657807.223410@ o13g2000cwo.goo glegroups.com.. .
      | Hi all,
      |
      | i'm doing a quite long treatment in a function, and i'm showing the
      | progress of the treatment with a progressbar. The code is something
      | like this :
      |
      | for each(entry in entries) // about 100 entries
      | {
      | TreatmentForOne Or2Secs();
      | this->progressBar1->PerformStep( );
      | }
      |
      |
      | during the debug, the debugger tells me that :
      |
      | Managed Debugging Assistant 'ContextSwitchD eadlock' has detected a
      | problem in 'd:\test\NetSen dDotNet\debug\N etSendDotNet.ex e'.
      | Additional Information: The CLR has been unable to transition from COM
      | context 0x189558 to COM context 0x189408 for 60 seconds. The thread
      | that owns the destination context/apartment is most likely either doing
      | a non pumping wait or processing a very long running operation without
      | pumping Windows messages. This situation generally has a negative
      | performance impact and may even lead to the application becoming non
      | responsive or memory usage accumulating continually over time. To avoid
      | this problem, all single threaded apartment (STA) threads should use
      | pumping wait primitives (such as CoWaitForMultip leHandles) and
      | routinely pump messages during long running operations.
      |
      |
      | Specially :
      | To avoid this problem, all single threaded apartment (STA) threads
      | should use pumping wait primitives (such as CoWaitForMultip leHandles)
      | and routinely pump messages during long running operations.
      |
      | So, how can i pumping messages ? or, should i use a thread (and how ?)
      |
      |
      | Thanks for your help
      |
      |
      | Nicolas H.
      |


      Comment

      • nicolas.hilaire@motorola.com

        #4
        Re: How can i implement a message pump with winforms ?

        >Call routinely CurrentThread->Join(0), this implicitely calls[color=blue]
        >CoWaitForMulti pleHandles and returns.[/color]
        [color=blue]
        >Willy.[/color]

        Thanks willy, this is working and pumping message.
        But on my form, i have a label and a progress bar.
        During this time, the progress bar is refreshed, but not the label.
        Should i call an explicit update ?

        This is my code :
        this->Show();
        this->Update();
        for each(entry in entries)
        {
        TreatmentForOne Or2Secs();
        this->progressBar1->PerformStep( );
        System::Threadi ng::Thread::Cur rentThread->Join(0);
        }
        this->Hide();

        ("this" is the form)

        Do you know why the label isn't refreshed ?

        Thanks in advance

        Nicolas

        Comment

        • nicolas.hilaire@motorola.com

          #5
          Re: How can i implement a message pump with winforms ?

          maybe it's better to use Invoke or BeginInvoke

          what do you think about it ?


          Best, Nicolas

          Comment

          • Carl Daniel [VC++ MVP]

            #6
            Re: How can i implement a message pump with winforms ?

            Willy Denoyette [MVP] wrote:[color=blue]
            > Call routinely CurrentThread->Join(0), this implicitely calls
            > CoWaitForMultip leHandles and returns.[/color]

            Is this not what Application.DoE vents was made for?

            Of course, performance will be better still if the work is done on a second
            thread, with UI updates sent through Control.BeginIn voke.

            -cd


            Comment

            • nicolas.hilaire@motorola.com

              #7
              Re: How can i implement a message pump with winforms ?

              >Is this not what Application.DoE vents was made for?
              [color=blue]
              >Of course, performance will be better still if the work is done on a second
              >thread, with UI updates sent through Control.BeginIn voke.[/color]

              I try to use BeginInvoke, but i can't undestand how it works !

              I try to do something like this

              ArrayList ^ GetList()
              {
              ArrayList ^ list = gcnew ArrayList();
              BuildListInAThr eadThatTakesTim e();
              return list;
              }

              Using Delegates and thread but i can't achieve to make it working,
              because that's my first thread with the dotnet framework. If you know
              how to do, or maybe a link that explains that, it will be great.

              Otherwise, i will use
              System::Threadi ng::Thread::Cur rentThread->Join(0);
              and make a
              label->update();

              ....

              Best,

              Nicolas

              Comment

              • Willy Denoyette [MVP]

                #8
                Re: How can i implement a message pump with winforms ?



                "Carl Daniel [VC++ MVP]" <cpdaniel_remov e_this_and_nosp am@mvps.org.nos pam>
                wrote in message news:Ox0Tl$KMGH A.2040@TK2MSFTN GP14.phx.gbl...
                | Willy Denoyette [MVP] wrote:
                | > Call routinely CurrentThread->Join(0), this implicitely calls
                | > CoWaitForMultip leHandles and returns.
                |
                | Is this not what Application.DoE vents was made for?
                |
                | Of course, performance will be better still if the work is done on a
                second
                | thread, with UI updates sent through Control.BeginIn voke.
                |
                | -cd
                |
                |
                Not really, DoEvents was invented for VB and do pump the windows queue. The
                managed wait services like Join() WaitOne() etc. do pump COM messages only
                (CoWaitForMulti pleHandles ), so this solves the OP's initial problem.
                However, now I see he's running this long running procedure on the UI
                thread, which is of course a NO NO in windows.

                Willy.



                Comment

                • Willy Denoyette [MVP]

                  #9
                  Re: How can i implement a message pump with winforms ?


                  <nicolas.hilair e@motorola.com> wrote in message
                  news:1139837896 .864140.251570@ g14g2000cwa.goo glegroups.com.. .
                  | >Call routinely CurrentThread->Join(0), this implicitely calls
                  | >CoWaitForMulti pleHandles and returns.
                  |
                  | >Willy.
                  |
                  | Thanks willy, this is working and pumping message.
                  | But on my form, i have a label and a progress bar.
                  | During this time, the progress bar is refreshed, but not the label.
                  | Should i call an explicit update ?
                  |
                  | This is my code :
                  | this->Show();
                  | this->Update();
                  | for each(entry in entries)
                  | {
                  | TreatmentForOne Or2Secs();
                  | this->progressBar1->PerformStep( );
                  | System::Threadi ng::Thread::Cur rentThread->Join(0);
                  | }
                  | this->Hide();
                  |
                  | ("this" is the form)
                  |
                  | Do you know why the label isn't refreshed ?
                  |
                  | Thanks in advance
                  |
                  | Nicolas
                  |

                  That means you are running your long running task on the UI thread, this is
                  something you should not do, run this on another thread and call Invoke or
                  BeginInvoke to update the progressBar, that way your UI will remain
                  responsive.

                  Willy.




                  Comment

                  • nicolas.hilaire@motorola.com

                    #10
                    Re: How can i implement a message pump with winforms ?

                    >That means you are running your long running task on the UI thread, this is[color=blue]
                    >something you should not do, run this on another thread and call Invoke or
                    >BeginInvoke to update the progressBar, that way your UI will remain
                    >responsive.[/color]

                    Yes, i'm running the task on the form class.

                    So, i'm going to use thread ... but, i just need something easy

                    something like this

                    Thread ^ t = gcnew Thread(gcnew ThreadStart(Thr eadProcess));
                    t->Start();
                    WaitForTheThrea dToTerminate();

                    Is this possible ? and how ?


                    Thanks for your help

                    Comment

                    • nicolas.hilaire@motorola.com

                      #11
                      Re: How can i implement a message pump with winforms ?

                      ok, i've tried this, but this is not working, as if the window is
                      frozen

                      I'm using ThreadPool and ManualResetEven t in my form class

                      Is this way of doing not good ?


                      System::Collect ions::ArrayList ^ getList()
                      {
                      list = gcnew System::Collect ions::ArrayList ();
                      manualEvent = gcnew System::Threadi ng::ManualReset Event(false);
                      System::Threadi ng::ThreadPool: :QueueUserWorkI tem(gcnew
                      System::Threadi ng::WaitCallbac k(this,
                      &myNameSpace::f rm_loading::Thr eadProcess));
                      manualEvent->WaitOne();
                      return list;
                      }

                      void ThreadProcess(S ystem::Object ^ stateInfo)
                      {
                      manualEvent->Reset();

                      this->progressBar1->Minimum = 0;
                      this->progressBar1->Maximum = nb;
                      this->progressBar1->Value = 0;
                      this->progressBar1->Step = 1;
                      this->Show();
                      this->Update();

                      for each (entry in entries)
                      {
                      TreatmentLongOn Entry();
                      this->progressBar1->PerformStep( );
                      }
                      this->Hide();
                      manualEvent->Set();
                      }


                      How can i correct ?

                      Thanks in advance

                      Best regards,

                      Nicolas

                      Comment

                      • Willy Denoyette [MVP]

                        #12
                        Re: How can i implement a message pump with winforms ?


                        <nicolas.hilair e@motorola.com> wrote in message
                        news:1139848904 .459040.45770@g 44g2000cwa.goog legroups.com...
                        | >That means you are running your long running task on the UI thread, this
                        is
                        | >something you should not do, run this on another thread and call Invoke
                        or
                        | >BeginInvoke to update the progressBar, that way your UI will remain
                        | >responsive.
                        |
                        | Yes, i'm running the task on the form class.
                        |
                        | So, i'm going to use thread ... but, i just need something easy
                        |
                        | something like this
                        |
                        | Thread ^ t = gcnew Thread(gcnew ThreadStart(Thr eadProcess));
                        | t->Start();
                        | WaitForTheThrea dToTerminate();
                        |
                        | Is this possible ? and how ?
                        |
                        |
                        | Thanks for your help
                        |


                        I would suggest you take some time to read the docs before you start using
                        multiple threads.
                        Anyway here is how you could init a background thread, probaly you must
                        initialize him to enter the STA as you seem to call into COM in your "task".

                        // in some handler (button click ??)

                        Thread ^ t = gcnew Thread(gcnew ThreadStart(thi s->MyLongRunningT ask));
                        t.SetApartmentS tate = ApartmentState. STA; // see above
                        t.IsBackground = true;
                        t->Start();
                        // no need to wait for the thread to terminate!!
                        ....


                        void MyLongRunningTa sk()
                        {
                        // keep the busy

                        }


                        Willy.


                        Comment

                        • nicolas.hilaire@motorola.com

                          #13
                          Re: How can i implement a message pump with winforms ?

                          >I would suggest you take some time to read the docs before you start using[color=blue]
                          >multiple threads.
                          >Anyway here is how you could init a background thread, probaly you must
                          >initialize him to enter the STA as you seem to call into COM in your "task".[/color]
                          [color=blue]
                          >// in some handler (button click ??)[/color]
                          [color=blue]
                          > Thread ^ t = gcnew Thread(gcnew ThreadStart(thi s->MyLongRunningT ask));
                          > t.SetApartmentS tate = ApartmentState. STA; // see above
                          > t.IsBackground = true;
                          > t->Start();
                          >// no need to wait for the thread to terminate!!
                          >...[/color]
                          [color=blue]
                          >void MyLongRunningTa sk()
                          >{
                          >// keep the busy
                          >
                          >}[/color]

                          Thanks for your help,

                          In fact, i need to wait for the thread to finish, because, as you can
                          see in my last post, i'm returning a list, that is built in the
                          longTask function.

                          Regards

                          Comment

                          • Willy Denoyette [MVP]

                            #14
                            Re: How can i implement a message pump with winforms ?


                            <nicolas.hilair e@motorola.com> wrote in message
                            news:1139852447 .035125.10910@g 43g2000cwa.goog legroups.com...
                            | >I would suggest you take some time to read the docs before you start
                            using
                            | >multiple threads.
                            | >Anyway here is how you could init a background thread, probaly you must
                            | >initialize him to enter the STA as you seem to call into COM in your
                            "task".
                            |
                            | >// in some handler (button click ??)
                            |
                            | > Thread ^ t = gcnew Thread(gcnew ThreadStart(thi s->MyLongRunningT ask));
                            | > t.SetApartmentS tate = ApartmentState. STA; // see above
                            | > t.IsBackground = true;
                            | > t->Start();
                            | >// no need to wait for the thread to terminate!!
                            | >...
                            |
                            | >void MyLongRunningTa sk()
                            | >{
                            | >// keep the busy
                            | >
                            | >}
                            |
                            | Thanks for your help,
                            |
                            | In fact, i need to wait for the thread to finish, because, as you can
                            | see in my last post, i'm returning a list, that is built in the
                            | longTask function.
                            |
                            | Regards
                            |

                            No, Waiting on a UI thread means rendering the UI non-responsive. I guess
                            you need the list to update the UI, well do this from the non UI thread
                            using Control->Invoke or BeginInvoke.

                            Willy.


                            Comment

                            • nicolas.hilaire@motorola.com

                              #15
                              Re: How can i implement a message pump with winforms ?

                              >No, Waiting on a UI thread means rendering the UI non-responsive. I guess[color=blue]
                              >you need the list to update the UI, well do this from the non UI thread
                              >using Control->Invoke or BeginInvoke.[/color]

                              Hi again and thanks for your answer. I tryed to implement the method
                              using BeginInvoke. But, the UI is still quite frozen (my progressbar is
                              refreshing, but the entire form is not). And when i put an other
                              application on top of the z-order, i can't go back to my window, during
                              the long task.

                              This is my code, i hope you can find why it's not working (I'm calling
                              the method getList(), that constructs a list, shows a form with a
                              progress bar during the construction, and returns me the list at the
                              end)


                              System::Collect ions::ArrayList ^ getList ()
                              {
                              list = gcnew System::Collect ions::ArrayList ();
                              int nb = 40;
                              this->progressBar1->Visible = true;
                              this->progressBar1->Minimum = 0;
                              this->progressBar1->Maximum = nb;
                              this->progressBar1->Value = 0;
                              this->progressBar1->Step = 1;
                              this->Show();
                              this->Update();
                              System::IAsyncR esult ^ res;

                              res = this->BeginInvoke(gc new InvokeMethod(th is,
                              &myProject::frm _loading::Updat eProgressBar), nullptr);
                              this->EndInvoke(res) ;
                              System::Threadi ng::Thread::Sle ep(1000);
                              this->Hide();

                              return list;
                              }

                              private:
                              void UpdateProgressB ar(void)
                              {

                              for (int i=0;i<40;i++)
                              {
                              list->Add(System::Co nvert::ToString (i));
                              this->progressBar1->PerformStep( );
                              System::Threadi ng::Thread::Sle ep(500);
                              }

                              }


                              Thanks a lot in advance

                              Comment

                              Working...