I am working on a program where multiple threads share common resource and thus synchronization is must while modifying this common resource.
Basic requirement:
- if one thread is writing, other thread (reader/writer) should wait till first complete
- if one thread is reading, other thread should wait if it is writer else if it can read data without waiting for first to complete
For that I have created a sample program with two Reader threads and tow Writer threads and implemented lock
on reading and writing the common resource (in example a string
).
It is like below.
object lockObj;
private string commonString;
public string CommonResource
{
get
{
lock (lockObj)
{
//adding sleep to magnify error condition when reading takes longer time
Thread.Sleep(1000 * 2);
return commonString;
}
}
set
{
lock (lockObj)
{
Thread.Sleep(1000 * 5);
commonString = value;
}
}
}
it works fine in restricting two simultaneous reading-writing or writing-writing, but it also restrict two simultaneous reading-reading on common data (which is not required and makes reading unnecessarily slow).
I can implement this by having addition Boolean flags which keeps track of reading and writing process and update their selves accordingly. like below
But I would prefer internal mechanism first (if any) to achieve this instead of creating my own way.
bool isReadingInProgress = false;
bool isWritingInProgress = false;
public string ReadData()
{
string val;
while (isWritingInProgress)
{
Thread.Sleep(10);
}
isReadingInProgress = true;
val = commonString;
Thread.Sleep(2 * 1000);
isReadingInProgress = false;
return val;
}
public void WriteData(string val)
{
while(isReadingInProgress || isWritingInProgress)
{
Thread.Sleep(10);
}
isWritingInProgress = true;
commonString = val;
Thread.Sleep(5 * 1000);
isWritingInProgress = false;
}
I am not comfortable on above code as then dependency on Boolean flags will be very high, when they two are in fact just a common resources (like string for which i want synchronization) for threads. So i have to make these Boolean thread safe too (correct me if i m wrong).
Is there any better approach to do this?
If no, should i go with locking (as i shown in first code) and have slow reading function or i should go with this Boolean without bothering to make them thread safe?
calling of this threads are like below
static void Main(string[] args)
{
commonResourceClass = new CommonResourceClass(); //class which holds data
Thread writerThread1 = new Thread(() => WriterThreadRunner("writer 1"));
Thread writerThread2 = new Thread(() => WriterThreadRunner("writer 2"));
Thread readerThread1 = new Thread(() => ReaderThreadRunner("reader 1"));
Thread readerThread2 = new Thread(() => ReaderThreadRunner("reader 2"));
writerThread1.Start();
readerThread1.Start();
writerThread2.Start();
readerThread2.Start();
}
static void WriterThreadRunner(string threadName)
{
while (true)
{
//commonResourceClass.CommonResource = "Written";
commonResourceClass.WriteData("Written");
}
}
static void ReaderThreadRunner(string threadName)
{
while (true)
{
//string Data = commonResourceClass.CommonResource;
string Data = commonResourceClass.ReadData();
}
}