MST

星途 面试题库

面试题:C#属性和索引器在多线程环境下的设计与优化

在多线程应用程序中,使用C#的属性和索引器可能会遇到线程安全问题。请设计一个包含属性和索引器的类,使其在多线程环境下高效且线程安全。详细说明你采取的同步机制,如何避免死锁,以及在性能优化方面的考虑,如使用锁的粒度控制、读写锁的应用场景等。
17.2万 热度难度
编程语言C#

知识考点

AI 面试

面试题答案

一键面试

类设计

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

public class ThreadSafeClass
{
    private readonly object _lockObject = new object();
    private readonly ReaderWriterLockSlim _rwLock = new ReaderWriterLockSlim();
    private int _propertyValue;
    private Dictionary<int, string> _indexerData = new Dictionary<int, string>();

    // 线程安全的属性
    public int Property
    {
        get
        {
            _rwLock.EnterReadLock();
            try
            {
                return _propertyValue;
            }
            finally
            {
                _rwLock.ExitReadLock();
            }
        }
        set
        {
            _rwLock.EnterWriteLock();
            try
            {
                _propertyValue = value;
            }
            finally
            {
                _rwLock.ExitWriteLock();
            }
        }
    }

    // 线程安全的索引器
    public string this[int index]
    {
        get
        {
            _rwLock.EnterReadLock();
            try
            {
                if (_indexerData.ContainsKey(index))
                {
                    return _indexerData[index];
                }
                return null;
            }
            finally
            {
                _rwLock.ExitReadLock();
            }
        }
        set
        {
            _rwLock.EnterWriteLock();
            try
            {
                if (_indexerData.ContainsKey(index))
                {
                    _indexerData[index] = value;
                }
                else
                {
                    _indexerData.Add(index, value);
                }
            }
            finally
            {
                _rwLock.ExitWriteLock();
            }
        }
    }
}

同步机制

  1. 读写锁(ReaderWriterLockSlim):对于属性的读取和索引器的读取操作,使用读锁(EnterReadLock),允许多个线程同时读取数据,提高并发性能。对于属性的写入和索引器的写入操作,使用写锁(EnterWriteLock),只允许一个线程进行写入,保证数据一致性。
  2. 对象锁(object):在需要更粗粒度的同步时,可以使用object锁。但在本示例中,由于读写锁已经能满足需求,object锁未被直接使用,只是作为一个示例存在。

避免死锁

  1. 锁获取顺序一致:确保在整个应用程序中,线程获取锁的顺序是一致的。例如,如果一个线程先获取_rwLock的写锁,再获取其他锁,那么其他线程也应该按照相同的顺序获取锁。
  2. 超时机制ReaderWriterLockSlim提供了带有超时参数的锁获取方法,如EnterReadLock(int millisecondsTimeout)EnterWriteLock(int millisecondsTimeout)。可以设置合理的超时时间,避免线程无限期等待锁,从而防止死锁。

性能优化

  1. 锁的粒度控制:使用ReaderWriterLockSlim而不是简单的lock关键字,减小锁的粒度。读操作可以并发执行,只有写操作才需要独占锁,提高了并发性能。
  2. 读写锁的应用场景:适用于读多写少的场景,如缓存系统。在这种场景下,大量的读操作可以并发执行,只有少量的写操作需要独占锁,从而提高系统的整体性能。