Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 多线程访问字符串列表,每次访问时移动指针_C#_.net - Fatal编程技术网

C# 多线程访问字符串列表,每次访问时移动指针

C# 多线程访问字符串列表,每次访问时移动指针,c#,.net,C#,.net,我有一个列表,假设其中有10个字符串。我将启动线程,一旦一个线程访问列表中的一个条目,我希望指针移动,这样当下一个线程想要访问它时,它将访问下一个条目。当我们在列表的底部时,指针移到顶部。请告知我如何才能做到这一点。 线程不会插入任何内容,只是读取,并且在运行时字符串列表不会更改,它是静态的。您可以使用 lock语句获取给定对象的互斥锁 对象,执行语句块,然后释放锁。虽然 当锁被持有时,持有锁的线程可以再次获取 松开锁。阻止任何其他线程获取锁 并等待直到释放锁 private static re

我有一个列表,假设其中有10个字符串。我将启动线程,一旦一个线程访问列表中的一个条目,我希望指针移动,这样当下一个线程想要访问它时,它将访问下一个条目。当我们在列表的底部时,指针移到顶部。请告知我如何才能做到这一点。 线程不会插入任何内容,只是读取,并且在运行时字符串列表不会更改,它是静态的。

您可以使用

lock语句获取给定对象的互斥锁 对象,执行语句块,然后释放锁。虽然 当锁被持有时,持有锁的线程可以再次获取 松开锁。阻止任何其他线程获取锁 并等待直到释放锁

private static readonly object Sync=new object();
私有int_指数=0;
私有只读列表_List=new List(){“blah”…};
...
公共字符串SafeGetNext()
{
锁定(同步)
{
尝试
{
返回_列表[_索引];
}
最后
{
_index=\u index>=\u list.Count-1?0:\u index+1;
}
}
}

好的评论由


我认为指出什么东西需要上锁是很重要的 什么没有,为什么没有。OP会拿走他需要锁的东西吗 只读数据?应该吗?有人写信给你吗?有没有 区别

在本例中,
在读取和索引修饰符周围形成一道屏障。在这种情况下,两者都很重要

原因是,这两个操作(在本例中)都需要是原子的(术语使用松散)。这意味着一次读取和相关的修改索引需要作为一个块进行,并且在所有线程之间是互斥的


另一方面,仅仅锁定索引修改是没有意义的,因为两个线程可以读取相同的值。同样,反过来说,仅仅锁定读取是没有意义的,因为两个线程可能具有相同的索引缓存值,并将尝试更新它,从而导致错误的索引。

类似于:

public class StringListManager
{
    private readonly object _lock = new object();
    private readonly List<string> _theStrings = new List<string>();
    private int _index = 0;

    //maybe you want to do this in a constructor??
    public void Initialize(IEnumerable<string> strings)
    {
        lock (_lock)
        {
            _theStrings.AddRange(strings);
        }
    }

    public string GetNextString()
    {
        lock (_lock)
        {
            var count = _theStrings.Count;
            if (count == 0)
            {
                return null; //or an empty string, your choice
            }

            var result = _theStrings[_index];
            ++_index;
            if (_index >= count)
            {
                _index = 0;
            }

            return result;
        }
    }

    public void ClearStrings()
    {
        lock (_lock)
        {
            _theStrings.Clear();
        }
    }
}
公共类StringListManager
{
私有只读对象_lock=新对象();
私有只读列表_theStrings=new List();
私有int_指数=0;
//也许你想在构造器里做这个??
公共void初始化(IEnumerable字符串)
{
锁
{
_字符串.AddRange(字符串);
}
}
公共字符串GetNextString()
{
锁
{
var count=_theStrings.count;
如果(计数=0)
{
返回null;//或空字符串,由您选择
}
var结果=_theStrings[_index];
++_指数;
如果(_index>=计数)
{
_指数=0;
}
返回结果;
}
}
公共无效清除字符串()
{
锁
{
_字符串。清除();
}
}
}

它可以编译,但没有经过很好的测试。

查找C#
关键字。您需要在
锁定
块内执行“移动到列表中的下一项,或从末尾移动到列表的开头”逻辑。确保使用引用类型的实例作为锁定的基础对象(我总是创建一个私有锁定对象(类型为
对象
):
私有对象_lock=new object();
并使用它。“我希望指针移动”在托管C语言中似乎是有问题的……你能想到并描述一种机制来跟踪接下来的元素吗?之后,告诉我们它是由多线程读取或写入的,还是两者兼备的。然后,考虑Flydog关于锁的建议并决定什么是锁定的。之后,向我们展示一些代码,并寻求更具体的问题的帮助。。我实际上不必上下移动列表中的项目,只需列表中的指针/上次使用字符串。因此,如果我有“A”、“B”、“C”和thread1,则取“A”然后开始工作,thread2将得到B,thread3将得到C,thread4将得到A等等。我要指出的是,托管C#中没有指针。您必须使用其他工具来跟踪下一个“处理”的元素,然后您必须使其线程安全。您可能需要删除“指针”这个词从你的问题标题和正文中。使用类似“索引”的内容或者一个同义词。C#有
不安全的
指针的概念,这不是你所说的。谢谢你,我将使用另一个答案中的代码,因为我没有足够的分数,我无法对你的答案进行投票,但感谢你提供了一个解决方案,我得到了两个解决方案是等价的。我的答案比较冗长,但是我的重点(特别是对于新的编码人员)是更喜欢清晰而不是优雅。不过,您要做的是将所有这些封装在一个类中,使锁、索引和字符串列表成为私有的。这样,就没有人可以(有意或无意地)胡闹了行为。正如@ChristopherPisz所指出的,您希望最小化锁定代码的范围。我的代码几乎都处于锁定状态,但通常您会得到很多未锁定的代码。@OracleJava请注意,我忘记了一个
=
,它应该是
=
,我认为指出需要锁定的代码是很重要的d什么不需要,为什么不需要。OP是否需要锁定只读数据?是否应该?是否有写入的内容?是否有区别?@ChristopherPisz确实不需要锁定本质上不变的字符串数组。这里唯一需要锁定的是“索引”。请注意,只要每个线程只访问其自己的数组区域(在本例中为单个元素),就不需要锁定对数组的写入操作。@AlexeiLevenkov ahh好的,我明白你的意思,是的,我同意。@AlexeiLevenkov确实再次
public class StringListManager
{
    private readonly object _lock = new object();
    private readonly List<string> _theStrings = new List<string>();
    private int _index = 0;

    //maybe you want to do this in a constructor??
    public void Initialize(IEnumerable<string> strings)
    {
        lock (_lock)
        {
            _theStrings.AddRange(strings);
        }
    }

    public string GetNextString()
    {
        lock (_lock)
        {
            var count = _theStrings.Count;
            if (count == 0)
            {
                return null; //or an empty string, your choice
            }

            var result = _theStrings[_index];
            ++_index;
            if (_index >= count)
            {
                _index = 0;
            }

            return result;
        }
    }

    public void ClearStrings()
    {
        lock (_lock)
        {
            _theStrings.Clear();
        }
    }
}