• 线程同步-使用ReaderWriterLockSlim类


    使用ReaderWriterLockSlim创建一个线程安全的机制,在多线程中对一个集合进行读写操作。ReaderWriterLockSlim代表了一个管理资源访问的锁,允许多个线程同时读取,以及独占写。

    代码Demo:

    using System;
    using System.Threading;
    using System.Collections.Generic;

    在Main方法下面加入以下代码片段:

    static ReaderWriterLockSlim _rw = new ReaderWriterLockSlim();
    static Dictionary<int, int> _items = new Dictionary<int, int>();

    static void Read()
    {
    Console.WriteLine("Reading contents of a dictionary");
    while (true)
    {
    try
    {
    _rw.EnterReadLock();
    foreach (var key in _items.Keys)
    {
    Thread.Sleep(TimeSpan.FromSeconds(0.1));
    }
    }
    finally
    {
    _rw.ExitReadLock();
    }
    }
    }
    static void Write(string threadName)
    {
    while (true)
    {
    try
    {
    int newKey = new Random().Next(250);
    _rw.EnterUpgradeableReadLock();
    if (!_items.ContainsKey(newKey))
    {
    try
    {
    _rw.EnterWriteLock();
    _items[newKey] = 1;
    Console.WriteLine("New key {0} is added to a dictionary by a {1}", newKey, threadName);
    }
    finally
    {
    _rw.ExitWriteLock();
    }
    }
    Thread.Sleep(TimeSpan.FromSeconds(0.1));
    }
    finally
    {
    _rw.ExitUpgradeableReadLock();
    }
    }
    }

    在Main方法中加入以下代码片段:

    new Thread(Read) { IsBackground = true }.Start();
    new Thread(Read) { IsBackground = true }.Start();
    new Thread(Read) { IsBackground = true }.Start();

    new Thread(() => Write("Thread 1")) { IsBackground = true }.Start();
    new Thread(() => Write("Thread 2")) { IsBackground = true }.Start();

    Thread.Sleep(TimeSpan.FromSeconds(30));

    工作原理

    当主程序启动时,同时运行了三个线程来从字典中读取数据,还有另外两个线程向该字典中写入数据。我们使用readerWriterLockSlim类来实现线程安全,该类转为这样的场景而设计。

    这里使用两种锁:读锁允许多线程读取数据,写锁在被释放前会阻塞了其它线程的所有操作。获取读锁时还有一个场景,即从集合中读取数据时,根据当前数据而决定是否获取一个写锁并修改该集合。一旦得到写锁,会阻止阅读者读取数据,从而浪费大量的时间,因此获取写锁后集合会处于阻塞状态。为了最小化阻塞浪费的时间,可以使用EnterUpgradeableReadLock和ExitUpgradeableReadLock方法。先获取读锁后读取数据。如果发现必须修改底层集合,只需使用EnterLock方法升级锁,然后快速执行一次写操作,最后使用ExitWriteLock释放写锁。

    本例,我们先生成一个随机数。然后获取读锁并检查该数是否存在于字典的键集合中。如果不存在,将读锁更新为写锁然后将该锁新键键入到字典中。始终使用try/finaly代码块来确保在捕获后一定会释放锁,这是一项好的实践。

    所有的线程都被创建为后台线程。主线程在所有后台线程完成后等待30秒。

  • 相关阅读:
    自助Linux之问题诊断工具strace
    Linux系统与程序监控工具atop教程
    Google C++单元测试框架(Gtest)系列教程之三——测试固件(Test fixture)
    SQLServer2005:在执行批处理时出现错误。错误消息为: 目录名无效
    无法为可更新的订阅设置发布服务器登录名
    忘记SQL SERVER帐户sa的密码
    SQL Server 2008 R2 跟踪标志
    sys.dm_os_volume_stats监控物理磁盘
    SQL SERVER 中常见的高可用方案
    Vim操作的四种模式
  • 原文地址:https://www.cnblogs.com/v-haoz/p/9262608.html
Copyright © 2020-2023  润新知