C# 基本线程问题

C# 基本线程问题,c#,winforms,multithreading,C#,Winforms,Multithreading,这个问题以前可能被以各种方式问过,但下面是我想做的。我将有一个带有许多选项卡的Windows窗体。每个选项卡将包含一个网格对象。对于用户创建的每个选项卡/网格,我希望从一个专用线程中派生一个,用不断到达的信息填充该网格的内容。有谁能举例说明如何安全地执行此操作 谢谢。在选项卡的初始化中(假设WinForms,除非我看到其他选项): 这显然是最简单的例子。您还可以使用线程池生成线程(这在服务器端应用程序中更常见) 如果您使用的是.NET 4.0,您还可以使用任务并行库,这也会有所帮助。在选项卡的初

这个问题以前可能被以各种方式问过,但下面是我想做的。我将有一个带有许多选项卡的Windows窗体。每个选项卡将包含一个网格对象。对于用户创建的每个选项卡/网格,我希望从一个专用线程中派生一个,用不断到达的信息填充该网格的内容。有谁能举例说明如何安全地执行此操作


谢谢。

在选项卡的初始化中(假设WinForms,除非我看到其他选项):

这显然是最简单的例子。您还可以使用线程池生成线程(这在服务器端应用程序中更常见)


如果您使用的是.NET 4.0,您还可以使用任务并行库,这也会有所帮助。

在选项卡的初始化中(假设WinForms,直到我看到其他选项):

这显然是最简单的例子。您还可以使用线程池生成线程(这在服务器端应用程序中更常见)


如果您使用的是.NET 4.0,您还可以使用任务并行库,这也会有所帮助。

您应该有一组线程,以便能够控制它们

List<Thread> tabs = new List<Thread>();

最后,在TabRefreshHandler中,您应该检查哪个是调用线程号,您将知道哪个是应该刷新的选项卡

您应该有一个线程数组,以便能够控制它们

List<Thread> tabs = new List<Thread>();

最后,在TabRefreshHandler中,您应该检查哪个是调用线程号,您将知道哪个是应该刷新的选项卡

您可以使用两种基本方法。选择在你的情况下最有意义的一个。通常情况下,没有正确或错误的选择。它们在许多情况下都能同样好地工作。每种方法都有其优缺点。奇怪的是,社区似乎过于频繁地忽视了拉法。我不知道这到底是为什么。我最近偶然发现了一个问题,在这个问题上,每个人都推荐推式方法,尽管这是拉式方法的完美情况(有一个可怜的灵魂,他确实与大众背道而驰,被否决,最终删除了他的答案,只留下我作为唯一的反对者)

推送方法

让工作线程将数据推送到表单中。您需要使用
ISynchronizeInvoke.Invoke
方法来完成此操作。这里的优点是,当每个数据项到达时,它将立即添加到网格中。缺点是必须使用昂贵的封送处理操作,如果工作线程获取数据的速度过快,UI可能会陷入困境

void WorkerThread()
{
  while (true)
  {
    object data = GetNewData();
    yourForm.Invoke(
      (Action)(() =>
      {
        // Add data to your grid here.
      }));
  }
}
拉法

让UI线程从工作线程中提取数据。您将让工作线程将新数据项排队到共享队列中,UI线程将定期将这些数据项出列。这里的优点是,您可以限制每个线程独立执行的工作量。队列是您的缓冲区,随着CPU使用的消长,它会收缩和增长。它还将工作线程的逻辑与UI线程分离。缺点是,如果您的UI线程没有足够快的轮询速度或保持工作线程,则工作线程可能会溢出队列。当然,数据项不会实时显示在网格上。但是,如果您将
System.Windows.Forms.Timer
间隔设置得足够短,则对您来说可能不是问题

private Queue<object> m_Data = new Queue<object>();

private void YourTimer_Tick(object sender, EventArgs args)
{
  lock (m_Data)
  {
    while (m_Data.Count > 0)
    {
      object data = m_Data.Dequeue();
      // Add data to your grid here.
    }
  }
}

void WorkerThread()
{
  while (true)
  {
    object data = GetNewData();
    lock (m_Data)
    {
      m_Data.Enqueue(data);
    }
  }
}
private Queue m_Data=new Queue();
private void YourTimer_Tick(对象发送方、事件args args)
{
锁定(m_数据)
{
而(m_Data.Count>0)
{
对象数据=m_data.Dequeue();
//在此处向网格添加数据。
}
}
}
void WorkerThread()
{
while(true)
{
对象数据=GetNewData();
锁定(m_数据)
{
m_数据排队(数据);
}
}
}

您可以使用两种基本方法。选择在你的情况下最有意义的一个。通常情况下,没有正确或错误的选择。它们在许多情况下都能同样好地工作。每种方法都有其优缺点。奇怪的是,社区似乎过于频繁地忽视了拉法。我不知道这到底是为什么。我最近偶然发现了一个问题,在这个问题上,每个人都推荐推式方法,尽管这是拉式方法的完美情况(有一个可怜的灵魂,他确实与大众背道而驰,被否决,最终删除了他的答案,只留下我作为唯一的反对者)

推送方法

让工作线程将数据推送到表单中。您需要使用
ISynchronizeInvoke.Invoke
方法来完成此操作。这里的优点是,当每个数据项到达时,它将立即添加到网格中。缺点是必须使用昂贵的封送处理操作,如果工作线程获取数据的速度过快,UI可能会陷入困境

void WorkerThread()
{
  while (true)
  {
    object data = GetNewData();
    yourForm.Invoke(
      (Action)(() =>
      {
        // Add data to your grid here.
      }));
  }
}
拉法

让UI线程从工作线程中提取数据。您将让工作线程将新数据项排队到共享队列中,UI线程将定期将这些数据项出列。这里的优点是,您可以限制每个线程独立执行的工作量。队列是您的缓冲区,随着CPU使用的消长,它会收缩和增长。它还将工作线程的逻辑与UI线程分离。缺点是,如果您的UI线程没有足够快的轮询速度或保持工作线程,则工作线程可能会溢出队列。当然,数据项不会实时显示在网格上。但是,如果您将
System.Windows.Forms.Timer
间隔设置得足够短,则对您来说可能不是问题

private Queue<object> m_Data = new Queue<object>();

private void YourTimer_Tick(object sender, EventArgs args)
{
  lock (m_Data)
  {
    while (m_Data.Count > 0)
    {
      object data = m_Data.Dequeue();
      // Add data to your grid here.
    }
  }
}

void WorkerThread()
{
  while (true)
  {
    object data = GetNewData();
    lock (m_Data)
    {
      m_Data.Enqueue(data);
    }
  }
}
private Queue m_Data=new Queue();
private void YourTimer_Tick(对象发送方、事件args args)
{
锁定(m_数据)
{
而(m_Data.Count>0)
{
对象数据=m_data.Dequeue();
//在此处向网格添加数据。
}
}
}
空工