【发布时间】:2013-10-23 08:16:43
【问题描述】:
我在不确定是否有必要的地方使用了 volatile。我很确定在我的情况下锁会是矫枉过正。阅读这个帖子(Eric Lippert 评论)让我对 volatile 的使用感到焦虑:When should the volatile keyword be used in c# ?
我使用 volatile 是因为我的变量在多线程上下文中使用,在该上下文中可以同时访问/修改该变量,但在其中我可以松散添加而不会造成任何伤害(参见代码)。
我添加了“易失性”以确保不会发生未对齐:仅读取变量的 32 位和另一个 fetch 上的其他 32 位,这可以通过在中间从另一个线程写入来打破。
我之前的假设(之前的陈述)真的会发生吗?如果不是,是否仍然需要使用“易失性”(选项属性修改可能发生在任何线程中)。
阅读前 2 个答案后。我想坚持这样一个事实,即代码的编写方式,如果由于并发性我们错过了一个增量(想从 2 个线程增加,但结果由于并发性只增加一个),这并不重要,如果至少变量“_actualVersion”递增。
作为参考,这是我使用它的代码部分。它仅在应用程序空闲时报告保存操作(写入磁盘)。
public abstract class OptionsBase : NotifyPropertyChangedBase
{
private string _path;
volatile private int _savedVersion = 0;
volatile private int _actualVersion = 0;
// ******************************************************************
void OptionsBase_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
_actualVersion++;
Application.Current.Dispatcher.BeginInvoke(new Action(InternalSave), DispatcherPriority.ApplicationIdle);
}
// ******************************************************************
private void InternalSave()
{
if (_actualVersion != _savedVersion)
{
_savedVersion = _actualVersion;
Save();
}
}
// ******************************************************************
/// <summary>
/// Save Options
/// </summary>
private void Save()
{
using (XmlTextWriter writer = new XmlTextWriter(_path, null))
{
writer.Formatting = Formatting.Indented;
XmlSerializer x = new XmlSerializer(this.GetType());
x.Serialize(writer, this);
writer.Close();
}
}
【问题讨论】:
-
不是您所要求的(因此添加为评论),但我可能会将 Save() 方法调用移至“_savedVersion = _actualVersion”行上方。这样,如果 Save() 抛出异常,_savedVersion 变量就不会被错误地更新。
-
为什么要从
Dispatcher线程事件中保存?! -
@Baldrick,由于多线程的含义,我无法按照您所说的(移动)进行操作(如果这样做,我可能会错过版本更改)。但是你部分正确,我应该防止我的代码出现异常。谢谢!
-
@Ahmed,好问题。在大多数情况下,我的 OptionBase 类将从 UI 线程进行修改,并且将同时修改许多属性。这样,我可以保证每次属性修改只保存一次。我想从界面中提取负载并保存(将其隐藏给用户)。它应该更易于使用。选项也可以在代码中的任何地方一一修改,通常在 UI 线程中。我更愿意确保不要一直管理保存。
-
@EricOuellet - 我发现这个答案最能帮助您了解它们如何协同工作 - stackoverflow.com/questions/154551/…
标签: c# multithreading performance dispatcher volatile