Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/336.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# InvalidOperationException:调用线程无法访问此对象,因为其他线程拥有它。_C#_Wpf_Multithreading - Fatal编程技术网

C# InvalidOperationException:调用线程无法访问此对象,因为其他线程拥有它。

C# InvalidOperationException:调用线程无法访问此对象,因为其他线程拥有它。,c#,wpf,multithreading,C#,Wpf,Multithreading,可能重复: 错误: The calling thread cannot access this object because a different thread owns it. 代码: 公共部分类主窗口:窗口 { 螺纹t; 布尔中断; 公共主窗口() { 初始化组件(); } 专用无效BTS_单击(对象发送方,路由目标) { 如果(t==null) { t=新螺纹(此。计算); t、 Start(); btss.Content=“停止”; } 其他的 { t、 中断(); } } 私有无

可能重复:

错误:

The calling thread cannot access this object because a different thread owns it.
代码:

公共部分类主窗口:窗口
{
螺纹t;
布尔中断;
公共主窗口()
{
初始化组件();
}
专用无效BTS_单击(对象发送方,路由目标)
{
如果(t==null)
{
t=新螺纹(此。计算);
t、 Start();
btss.Content=“停止”;
}
其他的
{
t、 中断();
}
}
私有无效计算()
{
int currval=2;
int-devide=2;
而(!中断)
{
对于(int i=2;i

这是什么原因造成的?我如何解决它?

您需要重新加入主UI线程才能影响UI。您可以检查是否需要,并在引用控件之前实现调用

private void calculate()
{
    if (InvokeRequired)
    {
        Invoke(new Action(() => calculate()));
    }
    else
    {
      //
    }
 }
不允许从非UI线程访问任何UI元素(
lblPrimes
)。您必须使用线程中的
Invoke
来执行此操作

以下是一个很好的教程:


您只能从主线程更新GUI

在worker方法(calculate())中,您试图将项添加到列表框中

lbPrimes.Items.Add(currval.ToString()); 
这导致了异常

您正在以非线程安全的方式访问控件。当一个没有创建控件的线程尝试调用它时,您将得到一个InvalidOperationException

如果要将项目添加到列表框中,则需要使用前面提到的代码调用required

例如:

private delegate void AddListItem(string item);

private void AddListBoxItem(string item)
{
    if (this.lbPrimes.InvokeRequired)
    {
        AddListItem d = new AddListItem(item);
        this.Invoke(d, new object[] { item});
    }
    else
    {
        this.lbPrimes.Items.Add(item);
    }
}

在Calculate()方法中调用此AddListBoxItem(…)方法,而不是直接尝试将项添加到listbox控件。

问题在于工作线程正在尝试访问不允许的UI元素。你得到的例外是警告你这一点。很多时候,你甚至都不明白。相反,您的应用程序将以不可预测和惊人的方式失败

您可以使用
Control.Invoke
将委托的执行封送到UI线程。此代理将执行
lbPrimes.Items.Add
操作。但是,在这种情况下,我不推荐这种方法。原因是它会减慢工作线程的速度

我的首选解决方案是让工作线程将
currval
添加到
ConcurrentQueue
。然后,UI线程将通过
System.Windows.Forms.Timer
定期轮询此集合,以将值出列并将其放入
列表框中。与使用
控件.Invoke相比,这有很多优点

  • 它消除了
    Invoke
    施加的工作线程和UI线程之间的紧密耦合
  • 它将更新UI的责任放在UI线程中,不管怎样,UI线程都应该属于该线程
  • UI线程可以指定更新的时间和频率
  • 工作线程不必等待UI响应
    Invoke
    请求。它将增加工作线程的吞吐量
  • 由于
    调用
    是一项代价高昂的操作,因此它的效率更高
  • 当尝试使用
    Invoke
    终止工作线程时,许多微妙的争用条件都会自然消失
下面是我的首选选项的外观

private void calculate()
{
  int currval = 2;
  int devide = 2;
  while (!interrupt)
  {
    for (int i = 2; i < currval/2; i++)
    {
      if (2 % i != 0)
      {
        queue.Add(currval); // ConcurrentQueue<int>
      }
    }
    currval++;
  }
}

private void Timer_Tick(object sender, EventArgs args)
{
  int value;
  while (queue.TryDequeue(out value))
  {
    lbPrimes.Items.Add(value.ToString());
  }
}
private void calculate()
{
int currval=2;
int-devide=2;
而(!中断)
{
对于(int i=2;i
我注意到了另外两个问题

  • Thread.Interrupt
    取消阻止BCL等待调用,如
    WaitOne
    Join
    Sleep
    等。您使用它没有任何用途。我想你要做的是设置
    interrupt=true
  • 您可能应该在
    for
    循环中中断
    ,而不是
    while
    循环。如果
    currval
    变得足够大,线程响应中断请求的时间将越来越长

Calculate
不是这里的问题,访问
lblPrimes
是。是的,确切地说是在Calculate中,因此调用返回到self。当然,你可以用不同的方法,把调用嵌套得更深一些,这只是一个例子。这是次优的,完全违背了使用线程的目标。您不希望在
Invoke
中完成整个计算,只希望更新标签。使用你的代码,线程没有做任何事情。它实际上完全取决于你在做什么,正如我说的,目的是展示如何解决问题,而不是为OP编写最优化的生产准备代码。这是一个客户端应用程序,在大多数情况下,它真的没有丝毫区别。我认为这个解决方案更容易理解和维护。
private void calculate()
{
  int currval = 2;
  int devide = 2;
  while (!interrupt)
  {
    for (int i = 2; i < currval/2; i++)
    {
      if (2 % i != 0)
      {
        queue.Add(currval); // ConcurrentQueue<int>
      }
    }
    currval++;
  }
}

private void Timer_Tick(object sender, EventArgs args)
{
  int value;
  while (queue.TryDequeue(out value))
  {
    lbPrimes.Items.Add(value.ToString());
  }
}