Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Please suggest a Generic Cross-Thread Safe Invocation technique

32 views
Skip to first unread message

zorrothef...@gmail.com

unread,
Jun 26, 2008, 3:05:42 AM6/26/08
to
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

Peter Duniho

unread,
Jun 26, 2008, 3:20:12 AM6/26/08
to
On Thu, 26 Jun 2008 00:05:42 -0700, <zorrothef...@gmail.com> wrote:

> [...]


> However, the above technique seems to be a bit klunky (IMO).

Yes, it is "klunky". IMHO, it's unfortunate that that's the model MSDN
continues to suggest everywhere.

> 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.

If you are using .NET 3.0 or later, Microsoft has introduced the "Action"
generic delegate types. There are a variety of them, handling zero up to
(I think) four parameters. In your example, rather than declaring a
specific delegate type, you'd just use "Action<ListView>" as the type.

However, IMHO it's better to avoid the whole MSDN-suggested approach
altogether, and use anonymous methods that are invoked unconditionally.
So instead of the mess you posted before, you'd have something like this:

public void ListClear(ListView list)
{
Invoke((MethodInvoker)delegate { list.Clear(); });
}

You could use the no-parameter "Action" delegate type instead if you like.

In practically all the examples I've run into, the method is always
initially being called from the wrong thread anyway, and so InvokeRequired
is always true the first time into the method anyway. But even when
that's not the case, there's no harm in just calling Invoke() directly.
It probably costs a little more performance-wise, but I suspect that in
most cases that performance difference is inconsequential (and you at
least get out of the check for InvokeRequired, which offsets at least a
little bit of the performance hit :) ).

> 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?

Sure. Microsoft could have simply done so in the situations where they
now throw the exception. Presumably they had some specific reason for not
doing so though. Perhaps the check for InvokeRequired is costly, for
example, and they didn't want the general case to suffer
performance-wise. I don't know. But the fact is, they didn't. I'm
satisfied just with simplifying the code as I've shown above. Works fine
for me. :)

Pete

DeveloperX

unread,
Jun 26, 2008, 6:35:58 AM6/26/08
to

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/2008/06/18/simplifying-ui-and-worker-threads-threadbarrier-revisited/


Peter, Google groups is working in Opera again :D

zorrothef...@gmail.com

unread,
Jun 26, 2008, 11:53:59 AM6/26/08
to
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.

> 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 Duniho

unread,
Jun 26, 2008, 2:30:25 PM6/26/08
to
On Thu, 26 Jun 2008 03:35:58 -0700, DeveloperX
<ianatho...@googlemail.com> wrote:

> 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/2008/06/18/simplifying-ui-and-worker-threads-threadbarrier-revisited/

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.

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

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

Pete

DeveloperX

unread,
Jun 27, 2008, 6:19:14 AM6/27/08
to
On Jun 26, 7:30 pm, "Peter Duniho" <NpOeStPe...@nnowslpianmk.com>
wrote:

> On Thu, 26 Jun 2008 03:35:58 -0700, DeveloperX  
>
> <ianathomeag...@googlemail.com> wrote:
> > 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.
>
> 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.
>
> > Peter, Google groups is working in Opera again :D
>
> 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.

0 new messages