1

サーバーアプリケーションを作りたいです。最初は、すべての接続を整理し、リストボックスにログを書き込むためのスレッドを作成する必要があります。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

さて、安全にアクセスできるInvokeUIスレッドにデリゲートをマーシャリングするために使用できます。ListBox

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

しかし、残念ながら、このオプションは劣っています。実際、これらのマーシャリング手法は一般的にひどいものです。勘違いしないでくれ。(など)の時間と場所はありますが、Invokeこれは多くの状況と同様に、それらの1つではありません。

  • 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メッセージキューがフラッディングする可能性はありません。
  • そして最後に、ワーカーはUIスレッドが何をしているのかをまったく気付かずに楽しくスピードを上げることができます。

ただし、このソリューションには欠点が完全にないわけではありません。ワーカースレッドの速度が向上したので、UIスレッドが消費できるよりも多くのアイテムをキューに生成することができます。通常は問題にはなりませんが、それに対処するためのテクニックがあります。

于 2012-05-11T04:09:42.797 に答える