1

我想做服务器应用程序。一开始它应该创建线程来组织每个连接并在 Listbox 中写入日志。我有问题,因为我不知道在哪里可以创建可以访问 Form1.Listbox1 的新线程。这是我尝试过的:

public class ServerLoop
{
    Form1 form1;
    public ServerLoop(Form1 f)
    {
        form1 = f;
    }
    public void loop()
    {
        form1.addConsoleMessage("test");
    }
}

和 Form1 类:

public partial class Form1 : Form
{
    public Thread tServerLoop;
    public ServerLoop serverLoop;

    public Form1()
    {
        InitializeComponent();
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        console.Items.Clear();
        players.Items.Clear();
        players.Items.Add("Witaj w serwerze");
        addConsoleMessage("test");
        serverLoop = new ServerLoop(this);
        tServerLoop = new Thread(serverLoop.loop);
        tServerLoop.Start();
    }

    private void connectButton_Click(object sender, EventArgs e)
    {

    }

    public void addConsoleMessage(String msg)
    {
        console.Items.Add(msg);
    }
}

任何人都知道我能做些什么来实现这一目标?

4

1 回答 1

5

好吧,您可以使用Invoke将委托编组回ListBox可以安全访问的 UI 线程。

public void loop() 
{
  form1.Invoke(new Action(
    () =>
    {
      form1.addConsoleMessage("test");
    }));
} 

但是,唉,这个选项是次要的。实际上,这些编组技术通常很糟糕。别弄错我的意思。(等等)有时间和地点Invoke,但这和许多情况一样,不是其中之一。

  • 代码很丑陋,因为你必须Invoke到处调用。
  • 它迫使您进入 UI 线程和工作线程紧密耦合的设计。
  • 工作线程决定 UI 的更新频率。
  • 这是低效的。
  • 它可以淹没 UI 消息队列(至少它可以BeginInvoke)。
  • 工作线程必须等待 UI 线程的响应才能继续(Invoke无论如何它都会继续)。

那么我将如何解决这个问题呢?好吧,当然是无聊的旧东西System.Windows.Forms.Timer和花哨的新ConcurrentQueue<T>东西。

public partial class Form1 : Form                    
{
  private ConcurrentQueue<string> queue = new ConcurrentQueue<string>();

  public Form1()                    
  {                    
    InitializeComponent();                    
  }                    

  private void Form1_Load(object sender, EventArgs e)                    
  {                    
    console.Items.Clear();                    
    console.Items.Add("test");
    players.Items.Clear();                    
    players.Items.Add("Witaj w serwerze");                    
    Task.Factory.StartNew(
      () =>
      {
        while (GetSomeCondition())
        {
          string value = GetSomeValue();
          queue.Enqueue(value);
        }
      });
  }                    

  private void YourTimer_Tick(object sender, EventArgs e)                    
  {                    
    string value;
    while (queue.TryDequeue(out value)
    {
      console.Items.Add(value);
    }
  }                                        
}                    

那么我们现在有什么。

  • 它看起来很优雅。
  • 我们的后台任务只知道一个队列。紧密耦合已被破坏。
  • UI 线程现在决定更新频率……它应该是这样的。
  • 它的效率要高得多。
  • UI 消息队列不可能被淹没。
  • 最后,worker 可以愉快地加速,完全不知道 UI 线程在做什么。

但是,该解决方案并非完全没有缺点。现在我们的工作线程正在加速,它可能会为队列产生更多的项目,然后是 UI 线程可以消耗的项目。这通常不是问题,但有一些技术可以解决这个问题。

于 2012-05-11T04:09:42.797 回答