bugfix> c# > 投稿

X秒ごとにシリアルCOMでフォルダー構造のサイズを報告するプログラムがあります。 また、ユーザーがシリアルCOM経由でコマンドを送信したときに、フォルダー構造内のすべてのファイルのリストを報告する機能もあります。

例として: ユーザーは10秒ごとにサイズ情報を取得しており、ある時点でファイルのリストを知りたいと思っています。そのため、COMポート経由で「1」を送信すると、プログラムはファイルのレポートを開始します。

私が抱えている問題は、2つの関数がCOMポートに同時に書き込むことができないため、例外をスローし始めることです。

私がやりたいのは、両方の機能をもう一方が終了するまで待機させることです。これが私のコードです。

これは、COMポートに書き込むための簡単な機能です。

private void ComWrite(string msg)
{
    ComPort.Write(msg);
}

これを次の2つの機能から呼び出します。

これはファイル名を報告します:

private void GetFileNames()
{
    fileNames = Directory.GetFiles(textBox1.Text, "*.wav", SearchOption.AllDirectories);
    for (int i = 0; i < fileNames.Length; i++)
    {
        ComWrite((fileNames[i] + "\r\n"));
    }
}

これはタイマー上にあり、フォルダーサイズを報告します。

public void OnTimedEvent(object source, ElapsedEventArgs elapsed)
{
    folderSize = DirSize(new DirectoryInfo(textBox1.Text)) / 1000000;
    string labelText = folderSize.ToString() + "Mb";
    label3.Text = labelText;
    if (checkBox1.Checked)
    {
        try
        {
            ComWrite(labelText + "\r\n");
            label9.Text = labelText;
        }
        catch (Exception)
        {
            MessageBox.Show("Please Open COMPORT before sending command");
        }
    }
}

非同期関数を実装するにはどうすればよいですか?

編集:要求されたコード。

フォームロード時のCOMポートのセットアップは次のとおりです。

   private void Form1_Load(object sender, EventArgs e)
    {
        label5.Text = "Idle";
        ComPort.BaudRate = Convert.ToInt32("9600");
        ComPort.DataBits = Convert.ToInt16("8");
        ComPort.StopBits = (StopBits)Enum.Parse(typeof(StopBits), "One");
        ComPort.Handshake = (Handshake)Enum.Parse(typeof(Handshake), "None");
        ComPort.Parity = (Parity)Enum.Parse(typeof(Parity), "None");
    }

そして、コンボボックスで選択したCOMポートを開くには、ボタンをクリックしてください:

  private void btnPortState_Click(object sender, EventArgs e)
    {
        try
        {
            if (btnPortState.Text == "COMPort Closed / Click to Open")
            {
                btnPortState.BackColor = Color.Green;
                btnPortState.Text = "COMPort Open / Click To Close";
                ComPort.PortName = Convert.ToString(cboPorts.Text);
                ComPort.Open();
            }
            else if (btnPortState.Text == "COMPort Open / Click To Close")
            {
                btnPortState.Text = "COMPort Closed / Click to Open";
                btnPortState.BackColor = Color.Firebrick;
                ComPort.Close();
            }
        }
        catch (Exception)
        {
            MessageBox.Show("You must select a COMPORT before opening it.");
        }
    }

回答 1 件
  • あなたが望むのは、あなたのCOMポートに対して行われた取引のための相互排除だと思います。

    問題が、2つの異なるスレッドが同時にcomportへの書き込みを開始できることである場合、セマフォを使用してこれを解決できます。

    あなたの場合、ファイル名を送信している間にディレクトリサイズが送信されると良くないと思います。だから、 ComWrite の中に単純に入れることはできません 。

    代わりに、以下を提案します。

    クラスで:

    //semaphore so only 1 Thread at a time can pass through
    private static Semaphore semaphore = new Semaphore(1, 1); //(1,1) -> see comments
    
    

    OnTimedEvent

    if (checkBox1.Checked)
    {
        try
        {
            semaphore.WaitOne(); //Increases semaphore counter
            ComWrite(labelText + "\r\n");
            semaphore.Release();
            label9.Text = labelText;
        }
        (...)
    
    

    そして

    private void GetFileNames()
    {
        semaphore.WaitOne();
        (...) //writing the file names to ComPort
        semaphore.Release();
    }
    
    

    セマフォは一種のカウンターのような働きをします。カウンターがその最大カウントに達すると、これ以上のスレッドは Wait を通過できません  電話して、順番を待っています。セマフォを解放すると、基本的にカウンターに減少するように指示され、待機中のスレッドが入ることが許可されます。

あなたの答え