简体   繁体   English

在线程应用程序中使用C#Volatile关键字

[英]Using the C# Volatile keyword in Threaded Application

I have a class that has a few arraylists in it. 我有一堂课,其中有一些arraylists。

My main class creates a new instance of this class. 我的主类创建了该类的新实例。 My main class has at least 2 threads adding and removing from my class with the arraylists in it. 我的主类至少有2个线程在其中添加了数组列表的类中添加和删除。 At the moment everything is running fine but I was just wondering if it would be safer to declare my class with the arraylists in it as volatile eg/ 目前一切运行良好,但我只是想知道将带有arraylists的类声明为volatile eg /是否更安全。

private volatile myclass;
myclass = new myclass();
......
myclass.Add(...)
myclass.Clear(..)

Using the volatile keyword will not make your code thread-safe in this example. 在此示例中,使用volatile关键字不会使您的代码成为线程安全的。 The volatile keyword is typically used to ensure that when reading or writing the value of a variable (ie class field) that the latest value for that variable is either read from main memory or written straight to main memory, rather than read from cache (eg a CPU register) for example. volatile关键字通常用于确保在读取或写入变量的值(即类字段)时,该变量的最新值是从主存储器中读取或直接写入主存储器,而不是从缓存中读取(例如例如CPU寄存器)。 The volatile keyword is a way of saying "do not use caching optimizations with this shared field", and removes the issue where threads may use local copies of a field and so not see each other's updates. volatile关键字是一种“不对共享字段使用缓存优化”的说法,它消除了线程可能使用字段的本地副本而看不到彼此更新的问题。

In your case the value of myclass is not actually being updated (ie you are not re-assigning myclass) so volatile is not useful for you, and it is not the update of the myclass variable you actually want to make thread-safe in this case anyway. 在您的情况下,myclass的值实际上没有被更新(即您没有重新分配myclass),因此volatile对您没有用,这也不是您实际上想要在其中使线程安全的myclass变量的更新。无论如何。

If you wish to make updating of the actual class thread-safe, then using a "lock" around "Add" and "Clear" is a straight-forward alternative. 如果您希望对实际的类进行线程安全的更新,则在“添加”和“清除”周围使用“锁定”是一种直接的选择。 This will ensure that only one thread at a time can do these operations (which update the internal state of myclass) and so should not be done in parallel. 这将确保一次仅一个线程可以执行这些操作(这将更新myclass的内部状态),因此不应并行执行。

A lock can be used as follows: 锁可以如下使用:

private readonly object syncObj = new object(); 
private readonly myclass = new myclass();
......

lock (syncObj)
{
    myclass.Add(...)
}

lock (syncObj)
{
    myclass.Clear(..)
}

You also need to add locking around any code that reads the state that is being updated by "Add", if that is the case although it does not appear in your example code. 您也需要在读取“添加”正在更新的状态的所有代码周围添加锁定,如果是这种情况,尽管它未出现在示例代码中,但是这种情况是可以的。

It may not be obvious when first writing multi-threaded code why you would need a lock when adding to a collection. 第一次编写多线程代码时可能并不明显,为什么在添加到集合时需要锁。 If we take List or ArrayList as an example, then the problem arises as internally these collections use an Array as a backing store, and will dynamically "grow" this Array (ie by creating a new larger Array and copying the old contents) as certain capacities are met when Add is called. 如果我们以List或ArrayList为例,则会出现问题,因为在内部这些集合使用Array作为后备存储,并会动态“增长”该Array(即通过创建一个更大的新Array并复制旧内容)来确定调用Add时容量已满。 This all happens internally and requires the maintenance of this Array and variables such as what current size the collection is (rather than the Length of the actual array which might be larger). 这一切都在内部发生,并且需要维护此Array和变量,例如集合的当前大小(而不是实际数组的Length可能更大)。 So Adding to the collection may involve multiple steps if the internal Array needs to grow. 因此,如果内部数组需要增长,则添加到集合中可能涉及多个步骤。 When using multiple threads in an unsafe manner, multiple threads may indirectly cause growing to happen when Adding, and thus trample all over each others updates. 当以不安全的方式使用多个线程时,多个线程可能会在添加时间接导致增长,从而践踏彼此之间的所有更新。 As well as the issue of multiple threads Adding at the same time, there is also the issue that another thread may be trying to read the collection whilst the internal state is being changed. 除了多线程添加在同一时间的问题,还存在另一个线程可能试图同时内部状态被改为收集的问题。 Using locks ensures that operations like these are done without interference from other threads. 使用锁可确保完成此类操作而不会受到其他线程的干扰。

At present, the code is wrong; 目前,代码是错误的; adding a volatile keyword won't fix it. 添加volatile关键字无法解决该问题。 It's not safe to use the .NET classes across threads without adding synchronisation. 在不添加同步的情况下跨线程使用.NET类是不安全的。

It's hard to give straightforward advice without knowing more about the structure of your code. 在不了解更多代码结构的情况下,很难给出直接的建议。 A first step would be to start using the lock keyword around all accesses to the list object; 第一步将是在对列表对象的所有访问周围开始使用lock关键字; however, there could still be assumptions in the code that don't work across multiple threads. 但是,代码中仍可能存在无法跨多个线程工作的假设。

It's possible to use a collection class that's already safe for multithreaded access, which would avoid the need for getting the lock keyword in the right place, but it's still possible to make errors. 可以使用已经对多线程访问安全的收集类,这样可以避免将lock关键字放在正确的位置,但是仍然可能出错。

Can you post some more of your code? 您还能发布更多代码吗? That way we can give more specific suggestions about making it thread safe. 这样,我们可以就使其线程安全提出更具体的建议。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM