【发布时间】:2018-07-12 20:33:55
【问题描述】:
更新:发现错误。我的代码按预期工作,但我的同事向我正在与之通信的设备添加了一个小代码。结果是它忽略了我的第二个命令,因为它正忙于做其他事情。 修复了它,现在它又可以工作了。
在一周的开始,我问了一个关于将串行端口的访问限制为一个实例的问题。
确实有人在那里帮助了我,并向我提到了SemaphoreSlim。
这在当时确实起到了作用,我认为就是这样。
现在几天后我终于解决了另一个主要问题,在测试它时我注意到信号量不再工作了。
我将代码回滚到之前的版本,在该版本中我刚刚实现了信号量并且它确实可以工作。 但即使是那个代码也不再工作了。
我的 Visual Studio、PC 或 Raspberry 中的任何内容都没有更改...
有人知道为什么理论上应该有效的东西现在不再有效了吗?
非常感谢这里的帮助:)
添加了我正在使用的代码的一个非常简短的版本。 通常我会处理进入 Int 或字符串数组的数据。 我还将进行 CRC16 验证,所有内容都将包含在 try/catch 块中,以便在异常发生时捕获它们。
但是,到目前为止,这就是我所需要的一切。 如果需要,我将尝试提供更详细的信息。让我知道。
当前行为: 第一个任务开始并且工作正常。 第二个任务没有启动,之后的每个新任务也没有启动。
预期行为: 开始第一个任务并完成它。 第一个任务完成后,加载第二个任务并完成它。 当我之后启动另一个任务时,它也应该运行它。
Mainpage.xaml
public MainPage()
{
this.InitializeComponent();
InitPort();
}
private async void getData_Click(object sender, RoutedEventArgs e)
{
// Call the async operations.
// I usually don't call the same operation twice at the same time but it's just a test here.
// In normal usage the data contains different sizes.
await getData();
await getData();
}
private async Task getData()
{
ReadData readData = new ReadData();
byte[] readOutput = await readData.ReadParaBlock();
DisplayTextBox.Text = BitConverter.ToString(readOutput);
}
public async void InitPort()
{
string success = await ReadWriteAdapter.Current.Init();
DisplayTextBox.Text = success;
}
ReadData.cs
public class ReadData
{
private ReadBlock readBlock = new ReadBlock();
public async Task<byte[]> ReadParaBlock()
{
// Load task into the semaphore
await ReadWriteAdapter.Current.semaphore.WaitAsync();
// start writing to device
await readBlock.Write();
// dropped check of recieved checksum because obsolete for test
// start reading from device
byte[] recievedArray = await readBlock.Read();
// release the task from semaphore
ReadWriteAdapter.Current.semaphore.Release();
return recievedArray;
}
}
ReadBlock.cs
public class ReadBlock
{
public async Task<uint> Write()
{
// Command sent to device to get data
byte[] WriteArray = System.Text.Encoding.ASCII.GetBytes("getdata");
return await ReadWriteAdapter.Current.WriteAsync(WriteArray);
}
public async Task<byte[]> Read()
{
byte[] ListenOut = await ReadWriteAdapter.Current.Listen(100);
// dropped data conversion because obsolete for test
return ListenOut;
}
}
ReadWriteAdapter.cs
public class ReadWriteAdapter
{
public SemaphoreSlim semaphore { get; private set; }
private static readonly Object lockObject = new object();
private static ReadWriteAdapter instance;
private DataWriter dataWriter = null;
private DataReader dataReader = null;
private SerialDevice serialPort = null;
public static ReadWriteAdapter Current
{
get
{
if (instance == null)
{
lock (lockObject)
{
if (instance == null)
{
instance = new ReadWriteAdapter();
}
}
}
return instance;
}
}
private ReadWriteAdapter()
{
this.semaphore = new SemaphoreSlim(1, 1);
}
// initialize the serial port and configure it
public async Task<string> Init()
{
string aqs = SerialDevice.GetDeviceSelector();
DeviceInformationCollection devices = await DeviceInformation.FindAllAsync(aqs, null);
if (devices.Any())
{
string deviceId = devices[0].Id;
serialPort = await SerialDevice.FromIdAsync(deviceId);
serialPort.WriteTimeout = TimeSpan.FromMilliseconds(1000);
serialPort.ReadTimeout = TimeSpan.FromMilliseconds(1000);
serialPort.BaudRate = 19200;
serialPort.Parity = SerialParity.None;
serialPort.StopBits = SerialStopBitCount.One;
serialPort.DataBits = 8;
serialPort.Handshake = SerialHandshake.None;
dataWriter = new DataWriter(serialPort.OutputStream);
dataReader = new DataReader(serialPort.InputStream);
}
return "found port";
}
// start to listen to the serial port
public async Task<byte[]> Listen(uint BufferLength)
{
byte[] listen = new byte[BufferLength];
dataReader = new DataReader(serialPort.InputStream);
listen = await ReadAsync(BufferLength);
if (dataReader != null)
{
dataReader.DetachStream();
dataReader.Dispose();
dataReader = null;
}
return listen;
}
// function to read and interpret the data from serial port
private async Task<byte[]> ReadAsync(uint ReadBufferLength)
{
Task<uint> loadAsyncTask;
byte[] returnArray = new byte[ReadBufferLength];
dataReader.InputStreamOptions = InputStreamOptions.Partial;
loadAsyncTask = dataReader.LoadAsync(ReadBufferLength).AsTask();
uint bytesRead = await loadAsyncTask;
if (bytesRead > 0)
{
dataReader.ReadBytes(returnArray);
}
return returnArray;
}
// write the data using the serial port
public async Task<uint> WriteAsync(byte[] data)
{
dataWriter.WriteBytes(data);
Task<uint> storeAsyncTask = dataWriter.StoreAsync().AsTask();
return await storeAsyncTask;
}
}
【问题讨论】:
-
这不是真正可以回答的。开始写一个尽可能小的minimal reproducible example
-
我用我使用的一些短代码编辑了我的主帖。我把它精简为非常重要的东西,但它仍然不能那样工作:/
-
您需要更具体地了解信号量是如何“不工作”的。你期待什么行为,你实际看到了什么?
-
我希望它能限制我对串行端口的访问。这意味着当我一个接一个地启动 2 个任务时,它应该启动第一个任务,完成后它应该启动第二个任务。但对我来说,它只完成第一个任务而不是第二个任务,然后当我手动尝试启动另一个任务时,它甚至都没有启动。
-
WaitAsync 之后,您应该将代码包装在 try-finally 中,并在 finally 中使用 Release,以确保您始终释放标志,即使抛出异常也是如此。正如 MikeStrobel 在他的回答中指出的那样,问题很可能在于您没有这样做,并且从 IO 方法抛出异常,因此永远不会调用您的发布。
标签: c# uwp win-universal-app windows-10-universal