c# - ReaderWriterLockSlim 阻塞读取,直到所有排队的写入完成

标签 c# multithreading locking thread-safety

我正在尝试使用 ReaderWriterLockSlim 类来管理列表。

这个列表读多写少,读快写慢。

我编写了一个简单的测试工具来检查锁的工作原理。

如果出现以下情况

Thread 1 - Start Write
Thread 2 - Start Read
Thread 3 - Start Write

那么结果如下

Thread 1 starts its write and locks the list.
Thread 2 adds itself to the read queue.
Thread 3 adds itself to the write queue.
Thread 1 finishes writing and releases the lock
Thread 3 aquires the lock and starts its write
Thread 3 finishes writing and releases the lock
Thread 2 performs its read

是否有任何方法可以更改锁的行为,以便在授予写锁之前允许在写锁之前排队的任何读取请求完成?

编辑:演示我遇到的问题的代码如下

public partial class SimpleLock : System.Web.UI.Page
{
    public static ReaderWriterLockSlim threadLock = new ReaderWriterLockSlim();

    protected void Page_Load(object sender, EventArgs e)
    {
        List<String> outputList = new List<String>();

        Thread thread1 = new Thread(
            delegate(object output)
            {
                ((List<String>)output).Add("Write 1 Enter");
                threadLock.EnterWriteLock();
                ((List<String>)output).Add("Write 1 Begin");
                Thread.Sleep(100);
                ((List<String>)output).Add("Write 1 End");
                threadLock.ExitWriteLock();
                ((List<String>)output).Add("Write 1 Exit");
            }
        );
        thread1.Start(outputList);

        Thread.Sleep(10);

        Thread thread2 = new Thread(
            delegate(object output)
            {
                ((List<String>)output).Add("Read 2 Enter");
                threadLock.EnterReadLock();
                ((List<String>)output).Add("Read 2 Begin");
                Thread.Sleep(100);
                ((List<String>)output).Add("Read 2 End");
                threadLock.ExitReadLock();
                ((List<String>)output).Add("Read 2 Exit");
            }
        );
        thread2.Start(outputList);

        Thread.Sleep(10);

        Thread thread3 = new Thread(
            delegate(object output)
            {
                ((List<String>)output).Add("Write 3 Enter");
                threadLock.EnterWriteLock();
                ((List<String>)output).Add("Write 3 Begin");
                Thread.Sleep(100);
                ((List<String>)output).Add("Write 3 End");
                threadLock.ExitWriteLock();
                ((List<String>)output).Add("Write 3 Exit");
            }
        );
        thread3.Start(outputList);

        thread1.Join();
        thread2.Join();
        thread3.Join();

        Response.Write(String.Join("<br />", outputList.ToArray()));
    }
}

最佳答案

Is there any way of changing the behaviour of the lock so that any Read requests that were queued before a write lock are allowed to complete before the write locks are granted?

几乎完全避免使用锁怎么样?在写入期间,您可以获取锁、复制原始数据结构、修改副本,然后通过用新引用替换旧引用来发布新数据结构。由于在数据结构“发布”后您永远不会修改它,因此您根本不需要锁定读取。

这是它的工作原理:

public class Example
{
  private object writelock = new object();
  private volatile List<string> data = new List<string>();

  public void Write(string item)
  {
    lock (writelock)
    {
      var copy = new List<string>(data); // Create the copy.
      copy.Add(item); // Modify the data structure.
      data = copy; // Publish the modified data structure.
    }
  }

  public string Read(int index)
  {
    return data[index];
  }
}

我们在这里利用的技巧是 data 变量引用的任何内容的不变性。我们唯一需要做的就是将变量标记为 volatile

请注意,此技巧仅在写入足够少并且数据结构足够小以保持复制操作便宜的情况下才有效。这不是一劳永逸的解决方案。它并不适合所有场景,但它可能适合您。

关于c# - ReaderWriterLockSlim 阻塞读取,直到所有排队的写入完成,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8242676/

相关文章:

javascript - 将 .Net LINQ 查询转换为 Angular 2 TypeScript/JavaScript

c# - 选择后组合框专注于文本的开头

c# - 如何在 BlockingCollection<T> 实例上进行可中断等待?

android - 重启后 USB 附件无法通信

java - 任何操作系统设置是否会影响 ExecutorService?

c++ - boost 互斥顺序

c# - 在没有过程的情况下将表的值插入数据库时​​出现错误 "cannot add an entity that already exists."

c# - 将字符串转换为 double C#

php - mysql 中的行锁

c# - C# 锁定语句中的 Nop 生成