0

Just try to learn Invoke/BeginInvoke, I encountered in that problem.

       // Update UI
       public void UpdateForm(string value) {
        txtLog.AppendText(value + "\r\n");
       }


       // Thread function
       private void readSocket() {
        string row = "";

        while (socket.Connected) {                
            row = socket.readLine();            

            if (IsControlValid(this))
                BeginInvoke((MethodInvoker)delegate { UpdateForm(String.Copy(row)); });                    

        }
    }

Using Invoke method my UI update with the correct text, instead if I use BegineInvoke I see wrong text, ie some text repeatedly a lot of time. I know that call

BeginInvoke((MethodInvoker)delegate { UpdateForm(row); });  

maybe "row" can be behavior like a shared variable rather than

BeginInvoke((MethodInvoker)delegate { UpdateForm(String.Copy(row)); });                    

I think that each BeginInvoke call create a "new" delegate, so using String.Copy must create another instance of string, but I see always wrong value (duplicates, ecc).

Where I'm wrong?

Kaiser69
  • 430
  • 8
  • 19
  • Why you need `string.Copy`? and what is the code of `UpdateForm`? – Alessandro D'Andria Sep 26 '13 at 18:19
  • I just added string.Copy to prevent that variable "row" was changed during the UpdateForm(). UpdateForm() is a method that run need to run in UI to update some stuff (in this case only a TextBox) – Kaiser69 Sep 26 '13 at 19:57

1 Answers1

6

maybe "row" can be behavior like a shared variable rather than

Yes, the row variable is captured - so whenever it's read, it's the latest value that's read. You should put the variable declaration inside the loop:

while (socket.Connected) {                
    string row = socket.readLine();

    if (IsControlValid(this)) {
        // Removed String.Copy call, as it was pointless
        BeginInvoke((MethodInvoker)delegate { UpdateForm(row); });
    }
}

Now you'll have a different variable for each iteration of the loop, so you won't be overwriting the previous value in one thread while you're reading it in the delegate.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • It works! But I need to know two other things: 1. Isn't the same thing, create a new variable each loop, or pass as argument a COPY of the variable? 2. How much is bad in performance/waste memory, create a new variable for each string that I've receive, when I only need a reference to it. With Invoke I resolve that problem, but I want to know what's the best deal with BeginInvoke – Kaiser69 Sep 26 '13 at 19:56
  • @Kaiser69: No, it's not the same thing - because you're imagining that the variable's *value* is captured by the anonymous method. It isn't. The *variable itself* is captured. The problem isn't with the way you're calling `UpdateForm` - it's that `row` is evaluated at the point when it's called. As for the memory: almost certainly insignificant compared with anything else you'll be doing. – Jon Skeet Sep 26 '13 at 19:58
  • Yep, I'm thinking a loop that reads a socket. Read about 10000 rows with a verage 200chars. If I multiply that value for each useless "new string variable", I guess that was a big waste of memory. Well, we have PC with tons of GB, so use them :) – Kaiser69 Sep 26 '13 at 20:21
  • Another question. Just for curiosity, there is a way to do the same thing, using string.Copy()? – Kaiser69 Sep 26 '13 at 20:23
  • @Kaiser69: No - because you'd still be calling `String.Copy` from within the anonymous method, so it would still pick up the new value of `row`. And if you call it *outside* the anonymous method, it's pointless because strings are immutable. – Jon Skeet Sep 26 '13 at 20:42
  • Just perfect! Thanks. Now I'm know where I'm wrong. Before that disclosure, I thought that anonymous method was evaluated instantly when I call BeginInvoke, instead it's called "when he wants" :) – Kaiser69 Sep 26 '13 at 20:53
  • @Kaiser69: Exactly - because it's executed on the UI thread asynchronously. That's the difference between `BeginInvoke` and `Invoke`. – Jon Skeet Sep 26 '13 at 21:02