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