Suz*_*ron 6 c# volatile interlocked lock-free
我想用两种方法创建一个类:
void SetValue(T value) 存储一个值,但只允许存储单个值(否则会抛出异常).T GetValue() 检索值(如果还没有值,则抛出异常).我有以下愿望/约束:
GetValue()只有在最新值不存在时才抛出异常(null):null在调用SetValue()另一个线程后,它不应该基于陈旧值抛出异常.GetValue()如果值不为null,则表示不需要刷新值.我提出了几种实现这一目标的方法,但我不确定哪些是正确的,哪些是有效的,为什么它们(正确)和(有效),以及是否有更好的方法来实现我想要的东西.
Interlocked.CompareExchange写入场Interlocked.CompareExchange从外地来读Interlocked.CompareExchange(ref v, null, null)对字段执行操作后将导致下一次访问获得的值至少与Interlocked.CompareExchange看到的值相同.代码:
public class SetOnce1<T> where T : class
{
private T _value = null;
public T GetValue() {
if (_value == null) {
// Maybe we got a stale value (from the cache or compiler optimization).
// Read an up-to-date value of that variable
Interlocked.CompareExchange<T>(ref _value, null, null);
// _value contains up-to-date data, because of the Interlocked.CompareExchange call above.
if (_value == null) {
throw new System.Exception("Value not yet present.");
}
}
// _value contains up-to-date data here too.
return _value;
}
public T SetValue(T newValue) {
if (newValue == null) {
throw new System.ArgumentNullException();
}
if (Interlocked.CompareExchange<T>(ref _value, newValue, null) != null) {
throw new System.Exception("Value already present.");
}
return newValue;
}
}
Run Code Online (Sandbox Code Playgroud)
volatile字段to write the value (with [Joe Duffy](http://www.bluebytesoftware.com/blog/PermaLink,guid,c36d1633-50ab-4462-993e-f1902f8938cc.aspx)'s#pragma to avoid the compiler warning on passing a volatile value byref`).volatile代码:
public class SetOnce2<T> where T : class
{
private volatile T _value = null;
public T GetValue() {
if (_value == null) {
throw new System.Exception("Value not yet present.");
}
return _value;
}
public T SetValue(T newValue) {
if (newValue == null) {
throw new System.ArgumentNullException();
}
#pragma warning disable 0420
T oldValue = Interlocked.CompareExchange<T>(ref _value, newValue, null);
#pragma warning restore 0420
if (oldValue != null) {
throw new System.Exception("Value already present.");
}
return newValue;
}
}
Run Code Online (Sandbox Code Playgroud)
代码:
public class SetOnce3<T> where T : class
{
private T _value = null;
public T GetValue() {
if (_value == null) {
// Maybe we got a stale value (from the cache or compiler optimization).
lock (this) {
// Read an up-to-date value of that variable
if (_value == null) {
throw new System.Exception("Value not yet present.");
}
return _value;
}
}
return _value;
}
public T SetValue(T newValue) {
lock (this) {
if (newValue == null) {
throw new System.ArgumentNullException();
}
if (_value != null) {
throw new System.Exception("Value already present.");
}
_value = newValue;
return newValue;
}
}
}
Run Code Online (Sandbox Code Playgroud)
代码:
public class SetOnce4<T> where T : class
{
private volatile T _value = null;
public T GetValue() {
if (_value == null) {
throw new System.Exception("Value not yet present.");
}
return _value;
}
public T SetValue(T newValue) {
lock (this) {
if (newValue == null) {
throw new System.ArgumentNullException();
}
if (_value != null) {
throw new System.Exception("Value already present.");
}
_value = newValue;
return newValue;
}
}
}
Run Code Online (Sandbox Code Playgroud)
我还可以使用Thread.VolatileRead()读取值,结合任何写入技术.
除了 (#3) 的方法之外,您的任何方法都lock无法正常工作。
看:
if (_value == null) {
throw new System.Exception("Value not yet present.");
}
return _value;
Run Code Online (Sandbox Code Playgroud)
这段代码不是原子的,也不是线程安全的,如果不在lock. 其他线程仍然有可能设置_value为和null之间。你可以做的是设置为局部变量:ifreturn
var localValue = _value;
if (localValue == null) {
throw new System.Exception("Value not yet present.");
}
return localValue;
Run Code Online (Sandbox Code Playgroud)
但它仍然可以返回摊位价值。你最好使用lock——清晰、简单、快速。
编辑:避免使用lock(this),因为this在外部可见,第三方代码可能会决定lock在您的对象上使用。
编辑2:如果永远不能设置空值,那么只需执行以下操作:
public T GetValue() {
if (_value == null) {
throw new System.Exception("Value not yet present.");
}
return _value;
}
public T SetValue(T newValue) {
lock (writeLock)
{
if (newValue == null) {
throw new System.ArgumentNullException();
}
_value = newValue;
return newValue;
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
789 次 |
| 最近记录: |