views:

46

answers:

3

I see there are a lot of questions regarding threads modifying items in a form; however, I just wanna read the state of a checkbox (for example) from a thread. So...

Is there any additional overhead to access the "Checked" state of a checkbox in a form (from a thread) -vs- creation of an bool that will reflect the state of that checkbox, and have the thread access the boolean instead?

+3  A: 

I would suggest storing the value in a bool field regardless of the threading issue; the CheckBox should be the visual representation of the data, not the data itself. This will lead to less coupled code, with less impact of you decide to change the UI.

Fredrik Mörk
@Ed, I would also be extremely careful about allowing the CheckBox to change the state of the bool field while the thread is running and actively monitoring it. For instance, if you're monitoring for true/false changes in your listening thread, it's very possible for the state of the field to change quickly from the first thread without the listening thread ever observing the change.
Dan Bryant
@Dan Bryant: but then the question is whether the thread is interested in the state (in which case the state observed when read is OK, even if it missed a change) or in a transition (in which case it can be argued that an XXXResetEvent is the more appropriate object to observe)
Remus Rusanu
+2  A: 

A thread cannot access any form UI elements, and that includes reading any property of a checkbox. The Control methods and properties must be invoked only from the main UI thread:

Use the InvokeRequired property to synchronize access to the control from multiple threads. For more information about multithreaded Windows Forms controls, see How to: Make Thread-Safe Calls to Windows Forms Controls

Remus Rusanu
+2  A: 

The answer is most definitely yes. The reason is because accessing UI control state correctly involves a lot of work. You basically have to marshal a method call onto the UI thread to access a control properly. That marshaling operation requires sending a message to the UI thread via the message pump that contains a delegate reference. The UI thread will eventually pick it up and execute it. Since I have never timed this operation I cannnot say for sure how expensive it is, but I suspect it is a nontrivial amount of time. It has to be done this way because UI controls have thread affinity. That means they can only be accessed on the thread that created them. To marshal a delegate use the Control.Invoke or Control.BeginInvoke methods.

Fredrik already mentioned one really good workaround for avoiding the marshaling operation. Here is what it might look like in code.

public partial class YourForm : Form
{
    // Make sure to mark this variable as volatile.
    private volatile bool m_Checked;

    private void YourForm_Load(object sender, EventArgs e)
    {
        m_Checked = YourCheckbox.Checked;
        var thread = new Thread(
            () =>
            {
                while (true)
                {
                  // This read will come from main memory since the
                  // variable is marked as volatile.
                  bool value = m_Checked;
                }
            });
        thread.Start();
    }

    private void YourCheckbox_CheckedChanged(object sender, EventArgs e)
    {
        // This write will be committed to main memory since the
        // variable is marked as volatile.
        m_Checked = YourCheckbox.Checked;
    }

}
Brian Gideon
Ok, I think this answers my question, but I wanna make sure I'm clear... So you're saying that logic like this inside a thread...if (checkbox_YADA.Checked)...else...actually context switches to the UI thread, retreives the value of the 'Checked' bool, and then returns that info to the calling thread? Yikes! If that's really the case, then it is HORRIBLY inefficient to access (even readonly) anything on the Form through a thread. Please confirm...Thanks.
Ed
@Ed: No, the switch to the UI thread is not automatic. It has to be done manually via `Control.Invoke`. The logic you just described will continue to run in the worker thread and, in fact, will probably work correctly most of the time especially since the `CheckBox.Checked` property is doing nothing more than reading an instance variable. However, there would still be a memory barrier issue and if the property was more complex and required reading the window handle or something then all hell could break loose and your application would fail unpredictably and spectacularly.
Brian Gideon