-1

When we try to update the UI from a different thread it throws an exception saying The calling thread cannot access this object because a different thread owns it. OK, that's fine to me.

But why doesn't the below mentioned code throw a similar exception? It's possible that thread t1 and t2 are writing to value at very same time.

public class myclass
{
    string  value;

    public myclass()
    {
        Thread t1 = new Thread(method1);
        t1.Start();
        Thread t2 = new Thread(method2);
        t2.Start();
    }

    public void method1()
    {
        while (true)
        {
            value = "method1";
        }
    }

    public void method2()
    {
        while (true)
        {
           value = "method2";
        }
    }
}
AndrewS
  • 8,196
  • 5
  • 39
  • 53
slash shogdhe
  • 3,943
  • 6
  • 27
  • 46
  • 1
    Please clarify your question – Yuval Itzchakov May 28 '14 at 17:26
  • 3
    You mention UI thread, but your code has no reference to a UI element. What is this code supposed to do? – David Crowell May 28 '14 at 17:27
  • Please edit title of you post to be specific - "does not work"/"have an issue" is not a good title for SO post. – Alexei Levenkov May 28 '14 at 17:32
  • What UI are you using? Winforms? WPF? – Nathan A May 28 '14 at 17:32
  • Why down vote, is i am asking something meaningless........ – slash shogdhe May 28 '14 at 17:35
  • 1
    @slashshogdhe The downvotes are likely due to question not being clear about what you're asking. Your question title and exception message in the question both refer to UI-related multithreading, whereas your code sample has nothing to do with UI. As such, it is unclear what you're having trouble with to answer conclusively. Clarify what exactly you're trying to ask, and I think that'll help with downvotes. – LB2 May 28 '14 at 17:46
  • 1
    Downvotes generally mean the users don't understand your question, or perhaps the title or other phrasing is confusing. It's a strong suggestion to reword or rewrite your question. I've made some edits that hopefully will clarify your question; take a look. – AndrewS May 28 '14 at 17:47

2 Answers2

2

UI controls have thread affinity. That means they should be accessed on the same thread they are created on. This is because WinForms/WPF is actually just a wrapper around Win32functionality and the code that manages your windows and child controls in Win32 is not thread safe. Hence your Form and child controls should only be accessed on the same thread they are created.ad that created them, which is the processes Main Thread.

On the contrary, class variables can be created, accessed and modified on any thread (assuming they are exposed to the caller). This means they are not Thread Safe unless you make them.

Yuval Itzchakov
  • 146,575
  • 32
  • 257
  • 321
  • 1
    _"which is the processes `Main Thread`"_ - I'm fairly sure that's not exactly true. UI thread is the one that created the window, and it doesn't have to be "main thread," though often it is... – LB2 May 28 '14 at 17:39
  • 1
    @LB2 Could you please extend on that. Maybe with an example of where the `UI Thread` isn't the `Main Thread` allocated by the OS? – Yuval Itzchakov May 28 '14 at 17:44
  • @YuvalItzchakov Sure, create a brand new WinForms project, and in `Main` put the following (before `Application.Run`): `Task.Factory.StartNew(() => { Form1 f2 = new Form1(); f2.ShowDialog(); });`. You'll see two forms created by two different threads. – LB2 May 28 '14 at 18:11
  • Oh, I see what you're saying. My answer was targeting the form created on application startup. – Yuval Itzchakov May 28 '14 at 18:35
  • 1
    http://stackoverflow.com/questions/10905844/creating-a-form-and-using-form-showdialog-on-a-background-thread – Yuval Itzchakov May 28 '14 at 18:37
  • I see - it read to me like a general statement rather than relative to OP's question, so that's why I jumped in. If you're targeting app start main form, then it is totally correct. And good link - I didn't know about those caveats. – LB2 May 28 '14 at 19:12
0

string is reference class and therefore its assignment is atomic. A ui control is much more complicate it tied ultimately to a message loop and a thread. There is no simple conversion between these two scenarios. Most variables can be accessed by multiple threads their behaviour may be undefined or incorrect. UI objects validate that the caller is on the correct thread or throw an exception.

Edit

This code is a small example of a race condition. Two threads will attempt to increment and then decrement a counter the same number of times. Sometimes you will not get the correct output.

public class myclass
{
    int value = 0;
    const int tries = 10000;
    public int Go()
    {
        Thread t1 = new Thread(method1);
        t1.Start();
        Thread t2 = new Thread(method2);
        t2.Start();
        t1.Join();
        t2.Join();
        return value;
    }

    public void method1()
    {
        for (int x = 0; x < tries; x++)
        {
            value++;
        }

    }
    public void method2()
    {
        for (int x = 0; x < tries; x++)
        {
            value--;   
        }
    }
}
class Program
{


    static void Main(string[] args)
    {
        var c = new myclass();
        int counter = 0; 
        for(int x  = 0 ; x < 100 ; x++)
        {
            if(c.Go() != 0)
            {
                Console.WriteLine("Iteration {0} doesn't = 0", x);
            }
        }

    }
rerun
  • 25,014
  • 6
  • 48
  • 78
  • Ok, can you give me some code that can crash, other then communicating with UI elements... – slash shogdhe May 28 '14 at 17:31
  • +1. @slashshogdhe `string value {get { return "";} set {throw new Exception();}}` - will throw all the time... not sure what sample you are looking for... – Alexei Levenkov May 28 '14 at 17:34
  • You won't always get a crash in any case where someone doesn't look for out of thread access. The problems that are created are race conditions and deadlocks both of which are much harder to detect and fix than a simple crash. – rerun May 28 '14 at 17:52