我正在尝试编写一个代表通过RS232连接与设备通信的类。该设备既可以读取也可以写入,可以由多个线程完成。
到目前为止,我已选择将该类设为单例类,因为只有一个与设备的连接应该存在才有意义。我还实现了两个接口IDataProvider
和IDataConsumer
。这些只是定义方法Boolean ReadData(out Object readData, params Object[] args)
和WriteData(Object inData, params Object[] args)
。除了界面,我还写了RS232Device
。这实现了对端口Open()
,Close()
,Read()
和Write()
的方法。
到目前为止,我的班级大纲如下。
public class DeviceIO : RS232Device, IDataProvider, IDataConsumer
{
public static DeviceIO Instance { get { return lazyInstance.Value; } }
private static readonly Lazy<DeviceIO> lazyInstance
= new Lazy<DeviceIO>(() => new DeviceIO());
private DeviceIO() : base() {}
public void ConfigurePort(SerialPortConfig inConfig)
{
Configure(inConfig);
}
public Boolean ReadData(out Object readData, params Object[] args)
{
readData = null;
return false;
}
public Boolean WriteData(Object inData, params Object[] args)
{
return false;
}
}
我现在的问题是如何使这个线程安全。我假设在ReadData
和WriteData
内,我会锁定Object
的某个实例。这就是我需要做的一切吗?基本上就像下面的修改一样?
我可以使用下面的Instance
并将其分发到各种线程,并且没有任何问题,其中两个线程可能会尝试同时写入设备吗?
public class DeviceIO : RS232Device, IDataProvider, IDataConsumer
{
public static DeviceIO Instance { get { return lazyInstance.Value; } }
private static readonly Lazy<DeviceIO> lazyInstance
= new Lazy<DeviceIO>(() => new DeviceIO());
private static readonly Object Schlage = new Object();
private DeviceIO() : base() {}
public void ConfigurePort(SerialPortConfig inConfig)
{
lock(Schlage)
{
Configure(inConfig);
}
}
public Boolean ReadData(out Object readData, params Object[] args)
{
lock (Schlage)
{
readData = null;
return false;
}
}
public Boolean WriteData(Object inData, params Object[] args)
{
lock (Schlage)
{
return false;
}
}
}
答案 0 :(得分:1)
我建议通过实现消息队列模式来更好地服务于此类场景。在这里,任何需要使用RS232工具的代码都会将请求排队到队列,并等待回复或反应。同时,正好一个线程将服务于该队列的业务端,一次一个地从队列中取出,通过从RS232端口发送和/或接收信息来执行它,然后继续进行下一个排队的消息。 / p>
这有助于简化代码流,并有助于防止死锁。所有实际访问RS232资源的代码都只在一个线程(您的队列服务线程)上执行。至于所有其他线程,他们只需要将他们的请求发布到队列 - 一个非常快速的操作,然后检查他们的响应。
实现这一目标的一种方法是:
_myMessageQueue = new ConcurrentQueue<Rs232Message>();
将新消息发布到您的消息队列:
_myMessageQueue.Enqueue( message );
并使用以下命令检索排队的消息:
bool isOk = _myMessageQueue.TryDequeue( out message );