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

标签 c# .net multithreading .net-3.5 volatile

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

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

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

最佳答案

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

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

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

锁的使用方式如下:

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

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

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

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

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

关于c# - 在线程应用程序中使用 C# Volatile 关键字,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3350925/

相关文章:

c# - 使用 .NET WebBrowser 控件显示需要 X509 证书的 HTML 内容

.net - .NET JIT 会内联一个调用另一个小函数的小函数吗?

c# - 如何从 C# 将 EXE 注册/取消注册为 COM 对象?

java - Tomcat 线程模型 - 每个请求模型中的线程是否处理与该请求相关的所有工作?

c# - 如果用户没有安装 .NET,我如何部署 C# 应用程序?

c# - 如何保护 WinForms ConnectionString

c# - 组合框选择的索引更改事件未在代码中触发

c# - 将 IsEnabled 和其他属性绑定(bind)到公共(public)属性,它是否像依赖属性一样工作?

python - 使用 dask 作为任务调度来并行运行机器学习模型

java - 监视阻塞操作