为什么我的对象与UI对象的线程访问不同?

时间:2014-05-28 17:24:10

标签: c# .net multithreading

当我们尝试从不同的线程更新UI时,会抛出一个异常The calling thread cannot access this object because a different thread owns it。好的,对我来说没问题。

但为什么下面提到的代码没有抛出类似的异常呢?线程t1和t2可能同时写入value

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";
        }
    }
}

2 个答案:

答案 0 :(得分:2)

UI控件具有线程关联性。这意味着应该在创建它们的同一个线程上访问它们。这是因为WinForms/WPF实际上只是Win32功能的包装器,管理Win32中的窗口和子控件的代码不是线程安全的。因此,您的表单和子控件只能在创建它们的同一个线程上访问。创建它们的那个,即进程Main Thread

相反,可以在任何线程上创建,访问和修改类变量(假设它们暴露给调用者)。这意味着除非你制作它们,否则它们不是Thread Safe

答案 1 :(得分:0)

string是引用类,因此它的赋值是原子的。 ui控件更复杂,它最终与消息循环和线程相关联。这两种情况之间没有简单的转换。大多数变量可以被多个线程访问,它们的行为可能是未定义的或不正确的。 UI对象验证调用者是否在正确的线程上或抛出异常。

修改

此代码是竞争条件的一个小例子。两个线程将尝试递增然后递减计数器相同的次数。有时你不会得到正确的输出。

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);
            }
        }

    }