Say I have the singleton class Singleton
that can read and write to a SerialPort
.
public sealed class Singleton
{
private static readonly Lazy<Singleton> lazy =
new Lazy<Singleton>(() => new Singleton());
public static Singleton Instance { get { return lazy.Value; } }
SerialPort commPort = new SerialPort();
private Singleton()
{
// Setup SerialPort
}
public String Read()
{
return commPort.ReadLine();
}
public void Write(String cmd)
{
commPort.WriteLine(cmd);
}
}
Now lets also say that I have multiple threads that access the device at the end of the SerialPort
. Some threads might only write to the SerialPort
and some might write and then read from the SerialPort
.
I want to make sure that while a thread is doing a read then write that it is not interrupted by another thread. Would the way to do this be to lock
on the Singleton.Instance
itself?
// Running on thread 1
public Boolean SetLEDStatus(int onOff)
{
lock(Singleton.Instance)
{
Singleton.Instance.Write("SET LED " + onOff.ToString() + "\r\n");
String status = Singleton.Instance.ReadLine();
return (status.Contains("SUCCESS")) ? true : false;
}
}
// Running on thread 2
public Boolean IsLEDOn()
{
lock(Singleton.Instance)
{
Singleton.Instance.Write("GET LED\r\n");
return (Singleton.Instance.ReadLine().Contains("ON")) ? true : false;
}
}
In this instance, if SetLEDStatus
and IsLEDOn
were called very close to the same time, I want to make sure that the SerialPort
is not written too twice before it is read. Does my use of locking prevent that?
Would this type of action be called "transactional IO"?
If this is indeed correct, are there any other more efficient ways to perform that same type of actions?
EDIT:
I understand why locking on the Singleton.Instance
could be bad, if something were to lock on Singleton.Instance
and then call a method in Singleton.Instance
that also tries to lock on itself, there would be a deadlock.
I originally planned to use a private object in the singleton to lock on. But I kind of talked myself out of it because of the situation outlined below. Which, I am not sure if this is correct.
(Using the two methods (minues the locking) above running on Thread1 and Thread2)
- Thread1 calls
Write
,Singleton.Instance
locks - Thread2 calls
Write
, but is blocked by the lock Singleton.Instance
completes theWrite
and releases the lock- Thread2s call to
Write
executes,Singleton.Instance
locks - Thread1 calls
Read
, but is blocked by the lock Singleton.Instance
completes theWrite
and releases the lock- Thread1s
Read
executes,Singleton.Instance
locks - Thread2 calls
Read
, but is blocked by the lock Singleton.Instance
completes theRead
and releases the lock- Thread2s
Read
is executed,Singleton.Instance
locks Singleton.Instance
completes theRead
and releases the lock
In this case there are two Writes
to the serial port in a row which is improper. I need to be able to do a Write
Read
back to back for some types of communication.