代码之家  ›  专栏  ›  技术社区  ›  Jiew Meng

调用线程无法访问此对象,因为其他线程拥有它

c#
  •  4
  • Jiew Meng  · 技术社区  · 14 年前

    好的,我当前的代码正在运行中,可能我会尝试对异步CTP执行相同的操作。但我还是想知道发生了什么。

    我有如下功能

    // In MainWindow.xaml.cs
    Task.Factory.StartNew(() => helper.Send());
    
    // In class HttpHelper
    public void Send()
    {
        // ...
    
        try
        {
            Status = Statuses.Uploading;
            // write to request stream
    
            Status = Statuses.Downloading;
            // write to response stream
    
            Status = Statuses.Idle; // the exception is thrown here
            // ...
        }
        catch (Exception e)
        {
            // ...
        }
    }
    

    完整代码 HttpHelper @pastebin . Send() 在线76

    我想知道为什么我会有例外?也许我在线程上做错了什么,但是为什么只有在成功设置 Status 财产2次?

    更新:原因。。。

    我有一个事件处理程序,正在听 StatusChanged 事件,在1if子句中,我忘记使用UI线程更新UI

    helper.StatusChanged += (s, evt) =>
    {
        _dispatcher.Invoke(new Action(() => txtStatus.Text = helper.Status.ToString())); // I used _dispatcher here correctly
    
        if (helper.Status == HttpHelper.Statuses.Idle || helper.Status == HttpHelper.Statuses.Error)
           progBar.IsIndeterminate = false; // but not here
    };
    
    3 回复  |  直到 14 年前
        1
  •  3
  •   Dan Tao    14 年前

    更新 :我错过了代码中的(为我辩护,很小)注释,该注释表明您使用的是WPF/Silverlight,而不是Windows窗体。

    尽管如此,看起来你还是能够理解我所说的基本要点并将其正确地应用到你自己的场景中(使用 Dispatcher.Invoke 而不是 Control.Invoke )干得好;)


    我猜你的 StatusChanged 事件更新 StatusLabel 控制你的用户界面?如果是这样的话,你需要 Invoke 来自UI线程的调用;例如:

    void HttpHelper_StatusChanged(object sender, EventArgs e)
    {
        var httpHelper = (HttpHelper)sender;
        UpdateStatus(httpHelper.Status);
    }
    
    void UpdateStatus(HttpHelper.Statuses status)
    {
        if (InvokeRequired)
        {
            Invoke(new Action<HttpHelper.Statuses>(UpdateStatus), status);
        }
        else
        {
            // Your code probably doesn't look like this;
            // it's just an example.
            statusLabel.Text = status.ToString();
        }
    }
    

    你可能会看到两次成功后又一次失败的原因有点超出我的理解,但我知道 状态标签 尤其是在涉及线程问题时,控件可能有点闪烁其词。我已经看到了直接从后台线程(通常是由于开发人员的疏忽)更新的代码,没有任何例外;在我看来,您两次幸运,一次不幸。

        2
  •  0
  •   Aliostad    14 年前

    Status 触摸用户界面?因为看起来是这样。

    我只能猜测,但我能想象 地位 更改用户界面上需要通过 Dispatcher.Invoke() .

        3
  •  -1
  •   Ali Tarhini    14 年前

    如果Status是全局变量,则会出现此异常,因为多个线程同时访问和更新它。我建议在它周围用一把锁