views:

398

answers:

4

Hi!

I want to read two properties from a worker thread. Here it is an example of the class:

public partial class FrmPrincipal : Form
{
    private int Height;
    private int Width;
    private string token;

    public FrmPrincipal()
    {
        InitializeComponent();
        ...
    }

    private void menuItem1_Click(object sender, EventArgs e)
    {
        Thread t = new Thread(RequestImage);
        t.Start();
    }

    private void RequestImage()
    {
        try
        {
            ...

            // I want to read these properties
            int alto = this.Height;
            int ancho = this.Width;
            this.token = "...";

            ...
        }
        catch (Exception ex)
        {
            ...
        }
    }

When menuItem1_Click it's executed it's starts a new thread using method RequestImage. In this method I need to read this.Height and this.Width and update the value of this.token.

How can I do this?

I'm programming an app for windows mobile (Compact Framework 2.0).

Thanks!

+4  A: 

I suggest you capture them in the click handler, and pass them into a delegate for the new thread. This is most easily done with a lambda expression for the actual ThreadStart:

public partial class FrmPrincipal : Form
{
    private string token;

    public FrmPrincipal()
    {
        InitializeComponent();
        ...
    }

    private void menuItem1_Click(object sender, EventArgs e)
    {
        int width = Width;
        int height = Height;
        Thread t = new Thread(() => RequestImage(width, height));
        t.Start();
    }

    private void RequestImage(int width, int height)
    {
        try
        {
            ...

            int alto = height;
            int ancho = width;
            this.token = "...";

            ...
        }
        catch (Exception ex)
        {
            ...
        }
    }
}
Jon Skeet
And how can update the value of this.token?
VansFannel
I think that tooken should be delared volatile.
Jacek Ławrynowicz
@yabcok: That depends on where token is used. I can imagine that it could be a good idea, but without knowing what token is used for, it is hard to tell.
Renze de Waal
A: 

Declaring shared variables volatile would be enought.

Edit: Could someone explain why this is not a good answer? I think that token should be volatile. Otherwise GUI thread could use cached value.

Jacek Ławrynowicz
Inside the method 'this' refers to a Form:Control and all the Control classes are explicitly not thread-safe and do some runtime checking. Look up the InvokeRequired property.
Henk Holterman
Declaring Width and Height volatile will (very likely) not help much, because Width and Height are related. If they change, they will probably both change. If (Width,Height) is changed from (10,10) to (20,20), using volatile can still result in (width,heigtht) becoming (20,10).
Renze de Waal
Inside the worker thread, it seems that Width and Height are only used once and then cached in alto and ancho. How would it help to make Width and Height volatile?
Renze de Waal
A: 

Change signature of your method to void RequestImage(object state) and call t.Start(this) to pass instance of the form into thread body.

Ihar Voitka
There's no need for that, as it's an instance method already. The problem is that you can't/shouldn't get Height and Width from a different thread, and calling Control.Invoke to get back to the UI thread seems a bit silly.
Jon Skeet
Sure, your idea with lambda expression is better since it reads Width and Height on UI thread.
Ihar Voitka
+2  A: 

Your code as posted doesn't require anything additional. However, it will only work properly if no other code will access the token member while the thread is running. Shared read/write access to a variable needs to be protected by a lock. But that's not all, you'll also have to ensure that the threads are synchronized properly, the thread that reads "token" should probably wait until the worker thread updated the value. Google for "producer consumer pattern" and you'll find plenty of literature on the subject.

Assuming in this case you need some kind of code in the UI thread to wait for RequestImage() to complete, then use its result, the easiest way to handle the synchronization is to let RequestImage() call Control.BeginInvoke() when it completes the job.

Note that you'll also need to handle the case where the UI thread terminates before the worker thread is completed. Not doing this is likely to produce an ObjectDisposed exception. The Q&D solution for that is to set the thread's IsBackground property to True. Do make sure that nothing nasty happens when the thread gets aborted.

Hans Passant