如何允许两个线程同时读取公共数据,但限制它们同时读写或写入

时间:2018-05-24 03:04:47

标签: c# .net multithreading

我正在开发一个程序,其中多个线程共享公共资源,因此在修改此公共资源时必须进行同步。

基本要求:

  • 如果一个线程在写,其他线程(读/写)应该等到第一次完成
  • 如果一个线程正在读取,其他线程应该等待,如果它是编写者,如果它可以读取数据而不等待第一个完成

为此,我创建了一个带有两个Reader线程和两个Writer线程的示例程序,并在读取和编写公共资源时实现了lock(例如string)。

就像下面一样。

    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;
            }
        }
    }

它可以很好地限制两个同时读写或写入,但它也限制了两个同时读取普通数据(这是不需要的,并使读取不必要地慢)。

我可以通过添加布尔标志来实现这一点,这些标志可以跟踪读写过程并相应地更新它们的自我。如下所示

但我更倾向于首先使用内部机制(如果有的话)来实现这一目标,而不是按照自己的方式创建。

    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;
    }

我对上面的代码感到不舒服,因为当它们两个实际上只是一个公共资源(比如我希望同步的字符串)时,对布尔标志的依赖性非常高。所以我必须使这些布尔线程安全(如果我错了,请纠正我)。

有没有更好的方法来做到这一点?

如果不是,我应该使用锁定(如我在第一个代码中所示)并且具有慢读取功能,或者我应该使用此布尔值而不必费心使它们的线程安全吗?

调用此线程如下所示

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();
    }
}

0 个答案:

没有答案