PC Review


Reply
Thread Tools Rate Thread

BeginInvoke and anonymous delegate

 
 
Dean Shimic
Guest
Posts: n/a
 
      3rd Sep 2006
void DisplayLines(object state)
{
for (int i = 0; i < 500; ++i)
{
int iCopy = i;
rtb.BeginInvoke((MethodInvoker)delegate
{
rtb.AppendText(iCopy + "\n");
});
}
MessageBox.Show("Done");
}

I call this function from the main thread with ThreadPool's
QueueUserWorkItem method. Since I'm accessing RichTextBox variable rtb from
the different thread than the one it was created on I have to call
BeginInvoke method.

Above code seems to work fine but I'm not sure if it's guaranteed to since
iCopy, the variable that is accessed from within the delegate, potentially
goes out of scope before delegate is invoked. Does this mean that iCopy can
be destroyed prior to delegate accessing it?
 
Reply With Quote
 
 
 
 
Vadym Stetsyak
Guest
Posts: n/a
 
      3rd Sep 2006
Hello, Dean!
You wrote on Sun, 3 Sep 2006 03:25:48 +0200:

DS> Above code seems to work fine but I'm not sure if it's guaranteed to
since
DS> iCopy, the variable that is accessed from within the delegate,
potentially
DS> goes out of scope before delegate is invoked. Does this mean that iCopy
can
DS> be destroyed prior to delegate accessing it?

iCopy will become a member of the hidden class
Have a look at for more details how anonymous delegates work
( http://blogs.msdn.com/oldnewthing/ar...02/686456.aspx )

--
Regards, Vadym Stetsyak.
Blog: http://vadmyst.blogspot.com


 
Reply With Quote
 
Marc Gravell
Guest
Posts: n/a
 
      3rd Sep 2006
A better solution is to build the string on the background thread
(ideally using a StringBuilder instance), and then perform a *single*
BeginInvoke to the UI thread to "rtb.AppendText(sb.ToString());". This
is a: more efficient (less message posting etc), but more importantly,
b: it is simpler: you don't need to worry about the lifetime so much.
Oh, and c: it will cause less UI updates, making the UI thread more
efficient, and smoother... but the UI will update in a single jump. If
this is a problem, you could always to a .Invoke whenever for instance
i % 100 is zero (and then once at the end) - the .Invoke avoids any
question of accessing the captured variable from two threads, and you
still see a progressively growing UI...

Marc

 
Reply With Quote
 
Dean Shimic
Guest
Posts: n/a
 
      3rd Sep 2006
On Sun, 3 Sep 2006 20:48:27 +0300, Vadym Stetsyak wrote:

> Hello, Dean!
> You wrote on Sun, 3 Sep 2006 03:25:48 +0200:
>
> DS> Above code seems to work fine but I'm not sure if it's guaranteed to
> since
> DS> iCopy, the variable that is accessed from within the delegate,
> potentially
> DS> goes out of scope before delegate is invoked. Does this mean that iCopy
> can
> DS> be destroyed prior to delegate accessing it?
>
> iCopy will become a member of the hidden class
> Have a look at for more details how anonymous delegates work
> ( http://blogs.msdn.com/oldnewthing/ar...02/686456.aspx )


Thanks.
 
Reply With Quote
 
Dean Shimic
Guest
Posts: n/a
 
      3rd Sep 2006
On 3 Sep 2006 12:10:45 -0700, Marc Gravell wrote:

> A better solution is to build the string on the background thread
> (ideally using a StringBuilder instance), and then perform a *single*
> BeginInvoke to the UI thread to "rtb.AppendText(sb.ToString());". This
> is a: more efficient (less message posting etc), but more importantly,
> b: it is simpler: you don't need to worry about the lifetime so much.
> Oh, and c: it will cause less UI updates, making the UI thread more
> efficient, and smoother... but the UI will update in a single jump. If
> this is a problem, you could always to a .Invoke whenever for instance
> i % 100 is zero (and then once at the end) - the .Invoke avoids any
> question of accessing the captured variable from two threads, and you
> still see a progressively growing UI...
>
> Marc


I know that building the string first would be more efficient but I
couldn't do that easily because the data (from the socket) comes in a
non-predictable way. I could get one message in 100 seconds or 100 messages
in 1 second.

As far as Invoke goes I believe it would give me some efficiency penalty
because the socket thread would have to wait for the string to be displayed
before it could continue.
 
Reply With Quote
 
Nicholas Paldino [.NET/C# MVP]
Guest
Posts: n/a
 
      3rd Sep 2006
You don't have to worry about this. The compiler generates a class
which is used to make the call to the anonymous delegate (which has the
method that is called). This class also will have members for the class
that contains this method (a field that ends in "this") as well as a member
for the iCopy variable.

In each iteration of the loop, a new instance of this class is created,
with the iCopy member field set, before the method to call is passed to
BeginInvoke.

Hope this helps.


--
- Nicholas Paldino [.NET/C# MVP]
- (E-Mail Removed)

"Dean Shimic" <(E-Mail Removed)> wrote in message
news:(E-Mail Removed)...
> void DisplayLines(object state)
> {
> for (int i = 0; i < 500; ++i)
> {
> int iCopy = i;
> rtb.BeginInvoke((MethodInvoker)delegate
> {
> rtb.AppendText(iCopy + "\n");
> });
> }
> MessageBox.Show("Done");
> }
>
> I call this function from the main thread with ThreadPool's
> QueueUserWorkItem method. Since I'm accessing RichTextBox variable rtb
> from
> the different thread than the one it was created on I have to call
> BeginInvoke method.
>
> Above code seems to work fine but I'm not sure if it's guaranteed to since
> iCopy, the variable that is accessed from within the delegate, potentially
> goes out of scope before delegate is invoked. Does this mean that iCopy
> can
> be destroyed prior to delegate accessing it?



 
Reply With Quote
 
Jon Skeet [C# MVP]
Guest
Posts: n/a
 
      4th Sep 2006
Nicholas Paldino [.NET/C# MVP] <(E-Mail Removed)> wrote:
> You don't have to worry about this. The compiler generates a class
> which is used to make the call to the anonymous delegate (which has the
> method that is called). This class also will have members for the class
> that contains this method (a field that ends in "this") as well as a member
> for the iCopy variable.
>
> In each iteration of the loop, a new instance of this class is created,
> with the iCopy member field set, before the method to call is passed to
> BeginInvoke.


Note that if you used "i" instead of "iCopy" you'd still get the same
behaviour - "i" would be captured in that case.

--
Jon Skeet - <(E-Mail Removed)>
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
 
Reply With Quote
 
Marc Gravell
Guest
Posts: n/a
 
      4th Sep 2006
Good reasoning, but you didn't mention the sockets ;-p

One other approach (more suitable in the sockets case) is to batch the
updates in a container class, and simply have a timer on the UI thread that
sucks the new lines from the collection and clears it - dummied below (note
thread safety); this avoids lots of messaging in terms of .BeginInvoke /
..Invoke, and performs fewer UI updates (e.g. set the timer to 250ms or
something). In almost all cases the lock will be uncontested (so very fast -
probably faster than the .BeginInvoke step), and even when contested the
block is short-lived (we don't update the UI while holding the lock).

I've used this approach to great effect when dealing with mid-to-high volume
updates from multiple threads.

Marc

readonly StringBuilder newLines = new StringBuilder();
public void AddLinesTimer_Tick(object sender, EventArgs args) {
string toAdd;
lock(newLines) {
toAdd = newLines.ToString();
toAdd.Length = 0; // wipe
}
if(toAdd.Length > 0) {
someControl.Text += toAdd;
}
}

public void SomeWorker() {
for(some loop) {
string newLine = "blah";
if(newLine.Length > 0) {
lock(newLines) { // lock per iteration, not for the entire loop
newLines.AppendLine(newLine);
}
}
}
}


 
Reply With Quote
 
Dean Shimic
Guest
Posts: n/a
 
      4th Sep 2006
On Mon, 4 Sep 2006 07:09:13 +0100, Jon Skeet [C# MVP] wrote:

> Nicholas Paldino [.NET/C# MVP] <(E-Mail Removed)> wrote:
>> You don't have to worry about this. The compiler generates a class
>> which is used to make the call to the anonymous delegate (which has the
>> method that is called). This class also will have members for the class
>> that contains this method (a field that ends in "this") as well as a member
>> for the iCopy variable.
>>
>> In each iteration of the loop, a new instance of this class is created,
>> with the iCopy member field set, before the method to call is passed to
>> BeginInvoke.

>
> Note that if you used "i" instead of "iCopy" you'd still get the same
> behaviour - "i" would be captured in that case.


Actually it doesn't. That is what I was using initially but if you add a
Thread.Sleep(10); in the delegate body output will end up being something
like 0, 500, 500, 500, etc.
 
Reply With Quote
 
Dean Shimic
Guest
Posts: n/a
 
      4th Sep 2006
On Mon, 4 Sep 2006 09:02:37 +0100, Marc Gravell wrote:

> Good reasoning, but you didn't mention the sockets ;-p
>
> One other approach (more suitable in the sockets case) is to batch the
> updates in a container class, and simply have a timer on the UI thread that
> sucks the new lines from the collection and clears it - dummied below (note
> thread safety); this avoids lots of messaging in terms of .BeginInvoke /
> .Invoke, and performs fewer UI updates (e.g. set the timer to 250ms or
> something). In almost all cases the lock will be uncontested (so very fast -
> probably faster than the .BeginInvoke step), and even when contested the
> block is short-lived (we don't update the UI while holding the lock).
>
> I've used this approach to great effect when dealing with mid-to-high volume
> updates from multiple threads.

[cut]

That's a clever way of doing it. I'll try and see how it behaves in my own
program.
 
Reply With Quote
 
 
 
Reply

Thread Tools
Rate This Thread
Rate This Thread:

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
BeginInvoke on a delegate Bob Altman Microsoft VC .NET 9 29th Jul 2008 10:14 PM
Anonymous Method vs. Anonymous Delegate Robert Howells Microsoft C# .NET 3 21st Oct 2007 08:08 AM
Control.BeginInvoke vs. delegate.BeginInvoke Valerie Hough Microsoft C# .NET 6 21st Oct 2005 11:14 AM
Cancelling a BeginInvoke on a delegate stand__sure Microsoft VB .NET 0 15th Jun 2005 06:52 PM
Call BeginInvoke on a Delegate Thomas Lerchner Microsoft Dot NET Compact Framework 1 10th Sep 2003 01:38 PM


Features
 

Advertising
 

Newsgroups
 


All times are GMT +1. The time now is 04:04 AM.