Please suggest a Generic Cross-Thread Safe Invocation technique

Z

zorrothefox.groups

Hi,
I have a C# Windows Form which creates a background
thread for downloading data to a serial port. In the background
thread, I need to update the GUI controls with the progress so far,
log messages etc. Initially I tried directly accessing the form
control from the background thread, which gave me a cross-thread
operation exception.

So I am now using the following approach:

1) Define a delegate and a corresponding member function for each
operation that I do.
2) In the background thread, I call the member function.
3) In the function, I check whether the control.InvokingRequired is
true
if true, I invoke the control in the proper thread
else
I call the control's relevant method (as this is
the main thread)

for example
1) delegate void ClearList(ListView list);
2) BackgroundThread()
{
ListClear(myForm.myListView);
}

2) public void ListClear(ListView list)
{
if(list.InvokeRequired == true)
{
ClearList cl = new ClearList(ListClear);
this.Invoke(cl,new object[]{list});
}
else
{
list.Clear();
}
}


However, the above technique seems to be a bit klunky (IMO). Is there
no way that this could be automated such that for each control's
function, I need not add a delegate? Since there are quite a few
controls that I need to access in the background thread (at least for
read purpose), the number of delegates and functions seem to be
excessive.

After all, at least logically, each control knows already which thread
it belongs to. Could it not be arranged in such a way that we add some
code to the form such that whenever a control is accessed, the form
automatically checks for the thread accessing the control, and passes
the same request onto the proper thread?

I know that this might be too much to ask, but given some kick-ass C#
features like reflection, it at least seems that there should be SOME
way of achieving this.

Thanks in advance,
Bharat
 
D

DeveloperX

Hi,
              I have a C# Windows Form which creates a background
thread for downloading data to a serial port. In the background
thread, I need to update the GUI controls with the progress so far,
log messages etc. Initially I tried directly accessing the form
control from the background thread, which gave me a cross-thread
operation exception.

So I am now using the following approach:

1) Define a delegate and a corresponding member function for each
operation that I do.
2) In the background thread, I call the member function.
3) In the function, I check whether the control.InvokingRequired is
true
           if true, I invoke the  control in the proper thread
           else
                    I call the control's relevant method (as this is
the main thread)

for example
1) delegate void ClearList(ListView list);
2)  BackgroundThread()
     {
          ListClear(myForm.myListView);
     }

2)  public void ListClear(ListView list)
        {
            if(list.InvokeRequired == true)
            {
                ClearList cl = new ClearList(ListClear);
                this.Invoke(cl,new object[]{list});
            }
            else
            {
                list.Clear();
            }
        }

However, the above technique seems to be a bit klunky (IMO). Is there
no way that this could be automated such that for each control's
function, I need not add a delegate? Since there are quite a few
controls that I need to access in the background thread (at least for
read purpose), the number of delegates and functions seem to be
excessive.

After all, at least logically, each control knows already which thread
it belongs to. Could it not be arranged in such a way that we add some
code to the form such that whenever a control is accessed, the form
automatically checks for the thread accessing the control, and passes
the same request onto the proper thread?

I know that this might be too much to ask, but  given some kick-ass C#
features like reflection, it at least seems that there should be SOME
way of achieving this.

Thanks in advance,
Bharat

Hello, this came up a few days ago, well similar. I suggested
SynchronizationContext briefly, I've found a blog post which explains
the ThreadBarrier pattern and may be of use.

http://blog.quantumbitdesigns.com/2008/06/10/stop-polluting-the-ui-thread-use-a-threadbarrier/

and also

http://blog.quantumbitdesigns.com/2...i-and-worker-threads-threadbarrier-revisited/


Peter, Google groups is working in Opera again :D
 
Z

zorrothefox.groups

Hi Pete and DeveloperX,
Thanks for the really
informational links and suggestions by both of you. Thanks also for
the fast replies. As I'm still sort of new to C# (having worked
entirely in MFC and VC6 up till around 6 months ago) and esp. to all
the latest features in C#, it'll probably take me a day or so to use
your information. But I know that the links you've provided will help
me solve my problem elegantly.

Thanks a lot,
Bharat.



Hi,
              I have a C# Windows Form which creates a background
thread for downloading data to a serial port. In the background
thread, I need to update the GUI controls with the progress so far,
log messages etc. Initially I tried directly accessing the form
control from the background thread, which gave me a cross-thread
operation exception.
So I am now using the following approach:
1) Define a delegate and a corresponding member function for each
operation that I do.
2) In the background thread, I call the member function.
3) In the function, I check whether the control.InvokingRequired is
true
           if true, I invoke the  control in the proper thread
           else
                    I call the control's relevant method (as this is
the main thread)
for example
1) delegate void ClearList(ListView list);
2)  BackgroundThread()
     {
          ListClear(myForm.myListView);
     }
2)  public void ListClear(ListView list)
        {
            if(list.InvokeRequired == true)
            {
                ClearList cl = new ClearList(ListClear);
                this.Invoke(cl,new object[]{list});
            }
            else
            {
                list.Clear();
            }
        }
However, the above technique seems to be a bit klunky (IMO). Is there
no way that this could be automated such that for each control's
function, I need not add a delegate? Since there are quite a few
controls that I need to access in the background thread (at least for
read purpose), the number of delegates and functions seem to be
excessive.
After all, at least logically, each control knows already which thread
it belongs to. Could it not be arranged in such a way that we add some
code to the form such that whenever a control is accessed, the form
automatically checks for the thread accessing the control, and passes
the same request onto the proper thread?
I know that this might be too much to ask, but  given some kick-ass C#
features like reflection, it at least seems that there should be SOME
way of achieving this.
Thanks in advance,
Bharat

Hello, this came up a few days ago, well similar. I suggested
SynchronizationContext briefly, I've found a blog post which explains
the ThreadBarrier pattern and may be of use.

http://blog.quantumbitdesigns.com/2008/06/10/stop-polluting-the-ui-th...

and also

http://blog.quantumbitdesigns.com/2008/06/18/simplifying-ui-and-worke...

Peter, Google groups is working in Opera again :D
 
D

DeveloperX

I think these articles are informative and useful food for thought.  
However, they don't seem to really be applicable here, and I definitely  
disagree with the implication that a) using Invoke() is "polluting the UI 
thread" and especially b) that the proposed alternative, using the  
SynchronizationContext class, avoids "polluting the UI thread".  If  
there's a pollution problem (and I don't feel that there is), the  
SynchronizationContext approach has exactly the same problem that  
Control.Invoke() does (seeing as they both wind up using the same  
mechanisms).

In this particular message thread, there is a specific need to execute the  
code on the GUI thread.  There's no way around that.  The simplest, most  
straightforward way to do that is to simply call Invoke() with an  
anonymous method that contains the code that needs to be executed.

It's good for people to know that SynchronizationContext exists and how to  
use it.  But in reality, Control.Invoke() (or Control.BeginInvoke()) is 
sufficient and perfectly appropriate for most needs.


Yay!  :)  Still, you might eventually find that using a real newsreader is  
better.  :)

Pete

Yep I take that on board, I've been playing with it in a mix of UI and
non UI contexts so it's quite interesting to me. I was semi wrong
about Opera being fixed. It works in standard view, but not tree view.
I'd love to use a real newsreader, but our pesky firewall is in the
way :( Fine at home of course.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top