写入串行 COM 端口时如何实现异步功能?
How can I implement asynchronous functions when writing to a Serial COM Port?
我有一个程序,每 X 秒通过串行 COM 报告文件夹结构的大小。
当用户也通过串行 COM 发送命令时,它还能够报告文件夹结构中所有文件的列表。
举个例子:
用户每 10 秒获取一次大小信息,有时他们想知道文件列表。所以他们通过 COM 端口发送一个“1”,然后程序开始报告文件。
我遇到的问题是两个函数不能同时写入 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");
}
然后您通过组合框打开您 select 的 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.");
}
}
我想你想要的是对你的 com 端口进行的任何交易的互斥。
如果问题是 2 个不同的线程可以同时开始写入 comport,这可以通过使用信号量来解决。
在您的情况下,我猜测如果在您发送文件名时传输目录大小是不好的。所以你不能简单地在 ComWrite
.
中进行 snychonize
相反,我建议如下:
在Class中:
//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();
}
Semaphores 有点像计数器。如果计数器达到其最大计数,则没有更多线程可以通过 Wait
调用并等待轮到它们。释放信号量基本上告诉计数器减少,现在允许等待线程进入。
我有一个程序,每 X 秒通过串行 COM 报告文件夹结构的大小。 当用户也通过串行 COM 发送命令时,它还能够报告文件夹结构中所有文件的列表。
举个例子: 用户每 10 秒获取一次大小信息,有时他们想知道文件列表。所以他们通过 COM 端口发送一个“1”,然后程序开始报告文件。
我遇到的问题是两个函数不能同时写入 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");
}
然后您通过组合框打开您 select 的 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.");
}
}
我想你想要的是对你的 com 端口进行的任何交易的互斥。
如果问题是 2 个不同的线程可以同时开始写入 comport,这可以通过使用信号量来解决。
在您的情况下,我猜测如果在您发送文件名时传输目录大小是不好的。所以你不能简单地在 ComWrite
.
相反,我建议如下:
在Class中:
//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();
}
Semaphores 有点像计数器。如果计数器达到其最大计数,则没有更多线程可以通过 Wait
调用并等待轮到它们。释放信号量基本上告诉计数器减少,现在允许等待线程进入。