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

发布于 2024-09-12 10:23:56 字数 240 浏览 3 评论 0原文

我有一个类,其中有一些数组列表。

我的主类创建了该类的一个新实例。我的主类至少有 2 个线程在我的类中添加和删除数组列表。目前一切都运行良好,但我只是想知道将我的类与其中的数组列表声明为易失性是否会更安全,例如/

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

I have a class that has a few arraylists in it.

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. 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/

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

酒与心事 2024-09-19 10:23:56

在此示例中,使用 volatile 关键字不会使您的代码成为线程安全的。易失性关键字通常用于确保在读取或写入变量(即类字段)的值时,该变量的最新值要么从主内存读取,要么直接写入主内存,而不是从缓存读取(例如例如,CPU 寄存器。易失性关键字是“不要对此共享字段使用缓存优化”的一种方式,它消除了线程可能使用字段的本地副本,因此看不到彼此的更新的问题。

在您的情况下, myclass 的值实际上并未被更新(即您没有重新分配 myclass ),因此 volatile 对您来说没有用,并且它不是您实际想要在此使线程安全的 myclass 变量的更新无论如何。

如果您希望使实际类的更新成为线程安全的,那么在“Add”和“Clear”周围使用“lock”是一种直接的替代方案。这将确保一次只有一个线程可以执行这些操作(更新 myclass 的内部状态),因此不应并行执行。

锁可以按如下方式使用:

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

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

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

您还需要在读取“添加”正在更新的状态的任何代码周围添加锁定,如果是这种情况,尽管它没有出现在示例代码中。

当第一次编写多线程代码时,为什么在添加到集合时需要锁可能并不明显。如果我们以 List 或 ArrayList 为例,那么问题就出现了,因为这些集合在内部使用数组作为后备存储,并且会动态“增长”这个数组(即通过创建一个新的更大的数组并复制旧的内容)调用 Add 时满足容量要求。这一切都发生在内部,并且需要维护该数组和变量,例如集合的当前大小(而不是可能更大的实际数组的长度)。因此,如果内部数组需要增长,添加到集合中可能会涉及多个步骤。当以不安全的方式使用多线程时,多个线程可能会间接导致添加时发生增长,从而践踏彼此的更新。除了多个线程同时添加的问题之外,还存在另一个线程可能在内部状态发生更改时尝试读取集合的问题。使用锁可确保此类操作的完成不会受到其他线程的干扰。

Using the volatile keyword will not make your code thread-safe in this example. The volatile keyword is typically used to ensure that when reading or writing the value of a variable (i.e. 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 (e.g. a CPU register) for example. 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.

In your case the value of myclass is not actually being updated (i.e. 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.

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.

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 (i.e. by creating a new larger Array and copying the old contents) as certain capacities are met when Add is called. 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). 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.

眼角的笑意。 2024-09-19 10:23:56

目前代码错误;添加 易失性 关键字无法解决此问题。在不添加同步的情况下跨线程使用 .NET 类是不安全的。

如果不了解更多关于代码结构的信息,就很难给出直接的建议。第一步是开始在对列表对象的所有访问周围使用 lock 关键字;但是,代码中仍然可能存在无法跨多个线程工作的假设。

可以使用对于多线程访问已经安全的集合类,这将避免需要在正确的位置获取 lock 关键字,但仍然可能会出错。

你能发布更多你的代码吗?这样我们就可以给出关于使其线程安全的更具体的建议。

At present, the code is wrong; adding a volatile keyword won't fix it. It's not safe to use the .NET classes across threads without adding synchronisation.

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; 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.

Can you post some more of your code? That way we can give more specific suggestions about making it thread safe.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文