Как реализовать асинхронные функции при записи на последовательный COM-порт? - PullRequest
0 голосов
/ 25 мая 2018

У меня есть программа, которая сообщает размер структуры папок через последовательный порт COM каждые X секунд.Он также имеет возможность сообщать список всех файлов в структуре папок, когда пользователь отправляет команду также через последовательный порт COM.

Например: пользователь получает информацию о размере каждые 10 секунд, в какой-то момент он хочет узнать список файлов.Таким образом, они посылают «1» через COM-порт, и программа начинает сообщать о файлах обратно.

Проблема, с которой я столкнулся, заключается в том, что две функции не могут одновременно записывать данные в COM-порт, поэтому он начинает выдавать исключения.

Я хотел бы, чтобы обе функции ожидали завершения другой.Вот мой код

Это простая функция для записи в COM-порт:

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

Я вызываю это из следующих двух функций:

В этом сообщается имя файла:

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 Ответ

0 голосов
/ 25 мая 2018

Я думаю, что вам нужно взаимное исключение для любой транзакции, сделанной на ваш com-порт.

Если проблема в том, что 2 разных потока могут начать запись в компорт одновременно, это может быть решенос помощью семафора.

В вашем случае я предполагаю, что было бы не хорошо, если бы размер каталога передавался во время отправки имен файлов.Так что вы не можете просто snychonize внутри 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 не смогут проходить и ожидают своей очереди.освобождение семафора в основном указывает счетчику на уменьшение, и ожидающие потоки теперь могут войти.

...