c# - 正确锁定线程安全的自生成列表 (C#)

标签 c# multithreading locking ienumerable generator

我有一个生成数字序列的单例 IEnumerable。该序列是可互换的(基本上是无限期的),我仅在需要时才生成序列中的下一个数字。

public class Generator:IEnumerable<long> {

    private Generator() { }

    private static volatile Generator instance=new Generator();
    private static readonly object syncRoot=new object();
    public static Generator Instance { get { return instance; } }

    private static List<long> numsList=new List<long>();

    private void GenerateNextNumber() {
        long number;
        //Code to generate next number
        numsList.Add(number);
    }

    private long GenerateToNthNumber(int n) {
        lock(syncRoot) {
            while(numsList.Count<n)
                GenerateNextNumber();
        }
        return numsList[n-1];
    }

    public static long GetNthNumber(int n) {
        return Instance.GenerateToNthNumber(n);
    }

    private class GeneratorEnumerator:IEnumerator<long> {
        private int index=0;

        public long Current { get { return GetNthNumber(index); } }

        public void Dispose() { }

        object System.Collections.IEnumerator.Current { get { return GetNthNumber(index); } }

        public bool MoveNext() {
            index++;
            return true;
        }

        public void Reset() {
            index=0;
        }
    }

    public IEnumerator<long> GetEnumerator() {
        return new GeneratorEnumerator();
    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
        return GetEnumerator();
    }
}

此代码可枚举并发线程中的数字并对其求和。有没有办法避免每次调用 GenerateToNthNumber 时都必须锁定?我试过这段代码:

    private long GenerateToNthNumber(int n) {
        if(numsList.Count<n) {
            lock(syncRoot) {
                while(numsList.Count<n)
                    GenerateNextNumber();
            }
        }
        return numsList[n-1];
    }

但是当测试通过多个并发线程中的数字进行枚举和求和时,并不是所有的结果都以相同的总和结束。如果可能的话,我的目标是在请求的数字已经生成的情况下进行非阻塞读取。有更好的方法吗?

最佳答案

List 的实现方式,无法在一个线程中安全地读取它而在另一个线程中写入它。我建议您改为使用嵌套的已知大小的数组,一旦分配,就永远不会被放弃(例如,一旦分配了一个包含 theList[15691] 的数组,该项目将永远不会被任何人保留其他数组)。这些东西可以很容易地用于实现只添加列表,该列表在添加项目时需要锁定,但本质上是线程安全的,无需锁定即可读取。

关于c# - 正确锁定线程安全的自生成列表 (C#),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14189469/

相关文章:

c# - 处理列表的扩展方法不起作用

c# - 读取已打印到控制台的值

java - 这个多线程同步代码有什么问题?

java - 内部/监视器锁和继承

c# - 跨多个应用程序域使用文件时读取\写入文件的最佳方式

c# - 将 T 转换为具有接口(interface)?

c# - 无法退出应用程序

multithreading - 在 sbcl lisp 中使用线程时,变量在 lisp 中未绑定(bind)

java - hibernate 线程何时在 Java 中继续执行?

SQL Server - key 更新死锁