本文介绍了这种使用通用 List 线程安全吗的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 System.Collections.Generic.List 我只在计时器回调中添加项目.定时器只有在操作完成后才会重新启动.

I have a System.Collections.Generic.List<T> to which I only ever add items in a timer callback. The timer is restarted only after the operation completes.

我有一个 System.Collections.Concurrent.ConcurrentQueue 用于存储上面列表中添加项目的索引.此存储操作也始终在上述相同的计时器回调中执行.

I have a System.Collections.Concurrent.ConcurrentQueue<T> which stores indices of added items in the list above. This store operation is also always performed in the same timer callback described above.

迭代队列并访问列表线程中对应项的读操作是否安全?

Is a read operation that iterates the queue and accesses the corresponding items in the list thread safe?

示例代码:

private List<Object> items;
private ConcurrentQueue<int> queue;
private Timer timer;
private void callback(object state)
{
    int index = items.Count;
    items.Add(new object());
    if (true)//some condition here
        queue.Enqueue(index);
    timer.Change(TimeSpan.FromMilliseconds(500), TimeSpan.FromMilliseconds(-1));
}

//This can be called from any thread
public IEnumerable<object> AccessItems()
{
    foreach (var index in queue)
    {
        yield return items[index];
    }
}

我的理解:即使列表在被索引时调整了大小,我也只是访问一个已经存在的项目,所以它是从旧数组还是从新数组读取都没有关系.因此这应该是线程安全的.

My understanding:Even if the list is resized when it is being indexed, I am only accessing an item that already exists, so it does not matter whether it is read from the old array or the new array. Hence this should be thread-safe.

推荐答案

是否记录是线程安全的?

如果不是,那么将其视为线程安全是愚蠢的,即使它是在这个实现中偶然出现的.线程安全应该设计.

If no, then it is foolish to treat it as thread safe, even if it is in this implementation by accident. Thread safety should be by design.

跨线程共享内存首先是一个坏主意;如果您不这样做,则您不必询问该操作是否是线程安全的.

Sharing memory across threads is a bad idea in the first place; if you don't do it then you don't have to ask whether the operation is thread safe.

如果必须这样做,请使用专为共享内存访问设计的集合.

If you have to do it then use a collection designed for shared memory access.

如果你不能这样做,那么使用锁.如果没有竞争,锁是便宜的.

If you can't do that then use a lock. Locks are cheap if uncontended.

如果由于锁一直处于争用状态而导致性能问题,那么解决该问题是通过更改线程架构而不是尝试执行诸如低锁代码之类的危险和愚蠢的事情.除了少数专家之外,没有人能正确编写低锁代码.(我不是其中之一;我也不写低锁代码.)

If you have a performance problem because your locks are contended all the time then fix that problem by changing your threading architecture rather than trying to do dangerous and foolish things like low-lock code. No one writes low-lock code correctly except for a handful of experts. (I am not one of them; I don't write low-lock code either.)

即使列表在被索引时调整了大小,我也只是访问一个已经存在的项目,所以它是从旧数组还是从新数组中读取都没有关系.

这种想法是错误的.正确的思考方式是:

That's the wrong way to think about it. The right way to think about it is:

如果列表被调整大小,则列表的内部数据结构正在发生变化.内部数据结构有可能在变异的中途变异为不一致的形式,在变异完成时将变得一致.因此,我的读者可以从另一个线程看到这种不一致的状态,这使得我的整个程序的行为不可预测.它可能会崩溃,可能进入无限循环,可能会破坏其他数据结构,我不知道,因为我正在运行的代码在状态不一致的世界中假设一致状态.

这篇关于这种使用通用 List 线程安全吗的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-01 19:20