Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/262.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/jsf-2/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
是无法解决的”;旗帜;C#/.NET中的线程安全?_C#_.net_Asynchronous_Thread Safety - Fatal编程技术网

是无法解决的”;旗帜;C#/.NET中的线程安全?

是无法解决的”;旗帜;C#/.NET中的线程安全?,c#,.net,asynchronous,thread-safety,C#,.net,Asynchronous,Thread Safety,(注意:我已经问过这个问题,但是答案是针对Java的,所以我对C#和.NET framework问了同样的问题。这不是重复的。) 我已经使用这个模式有一段时间了,但我最近才开始认为这样做可能不好。基本上,我使用这种模式的一些变体: public class SampleAsync { public SampleAsync() { } private bool completed; public void Start() { var worker

(注意:我已经问过这个问题,但是答案是针对Java的,所以我对C#和.NET framework问了同样的问题。这不是重复的。)

我已经使用这个模式有一段时间了,但我最近才开始认为这样做可能不好。基本上,我使用这种模式的一些变体:

public class SampleAsync
{
    public SampleAsync() { }

    private bool completed;
    public void Start()
    {
        var worker = new BackgroundWorker();
        worker.DoWork += (sender, e) => {
            //... do something on a different thread
            completed = true;
        };
        worker.RunWorkerAsync();
    }

    public void Update()
    {
        if (!completed) return;
        //... do something else
    }
}
*用户负责确保只调用一次
Start
<无论何时何地都会调用代码>更新


我一直认为这在C#/the.NET framework中是线程安全的,因为即使没有严格同步,我也只将
completed
设置为true。一旦观察到它是
true
,它将不会重置为
false
。它在构造函数中被初始化为false,根据定义这是线程安全的(除非你在其中做了一些愚蠢的事情)。那么,以这种方式使用不可设置的标志是线程安全的吗?(如果是,它是否提供了任何性能优势?)


谢谢

您的代码是线程安全的,因为
bool
是一种原子类型

MSDN:

以下数据类型的读写是原子的:bool、char、, byte、sbyte、short、ushort、uint、int、float和引用类型。在里面 添加、读取和写入中具有基础类型的枚举类型 前面的列表也是原子的。其他类型的读写, 包括long、ulong、double和decimal,以及用户定义的 类型不能保证是原子的。除了图书馆 为此目的而设计的功能,不保证原子 读修改写,例如在递增或递减的情况下

见:

请用
volatile
标记您的字段:

 private volatile bool completed;
MSDN:

volatile关键字表示可以在中修改字段 通过诸如操作系统、硬件或 并发执行线程


请参阅:

它严重依赖于目标体系结构。英特尔处理器有一个强大的内存模型,所以你倾向于这样的代码。但是抖动可能会把你搞砸。例如,x86 jitter易于将变量存储在cpu寄存器中,特别是当if()语句出现在紧循环中时。而且只有在发布版本中才能做到这一点,这是一场可怕的调试噩梦。声明变量易失性是一个带帮助。x64抖动不需要这样,至少在其当前版本中是这样。但在ARM和安腾等内存较弱的处理器上,创可贴往往无法阻止出血。他们当然不能保证变量的更新状态很快在另一个线程中可见。线程调度程序倾向于刷新cpu缓存。最终


做得不对是没有意义的。使用适当的同步对象,如AutoResteEvent。或者互锁。如果您担心周期,请比较Exchange()。

在C#和Java中?否则它是线程安全的吗?如果不使用
volatile
,则“一旦观察到它为真”可能永远不会发生。为什么不使用后台工作人员的
IsBusy
属性来确定它是否已完成?我可以想象,他们确保可以从任何线程安全地访问它。@Servy我并不是真的在问
BackgroundWorker
——这只是为了演示。关键是
completed
在不同的线程中设置,不一定在线程生命周期结束时设置。@overyou00我的观点是这就是为什么存在
BackgroundWorker
类的具体原因;帮助管理最常见用例中线程之间的同步。您应该学会利用这一点……但如果您使用
[FieldOffset]
[StructLayout]
显式对齐字段,则所有赌注都将无效。请参阅。这是否保证对该字段的写入会传播到其他线程?我不这么认为。该值可能已注册。对
已完成的
的写入本身可能是原子的且“安全的”,但如果
更新
已完成的
的值缓存在寄存器中(或其他具有相同效果的转换),则
更新可能永远看不到该值。@usr:你是对的。这就是为什么程序员应该使用
volatile
来防止缓存。@virtlink:这不是100%正确的。所有布尔值
True
都是相同的:它们都按位等于新的Int32(1)。否则,当使用
Object.Equals时,VB.NET库中的
True
将不等于C库中的
True
。我只是尝试了一个显式布局的结构,它有一个bool和一个int相互重叠。所以OP实际上仍然在修改一位。但是我想你是对的,如果布尔值中的任何位被设置为两次写入操作的一部分,那么
Update
方法仍然会收到正确的信号。volatile是否保证直接存储字段并始终从内存重新加载?(这两个属性都是实现此功能所必需的)。我不清楚volatile到底提供了什么保证。@usr:你还需要另一个属性——它不是提前写的,也不是推测性的。+1你的最后一段总结得很好。你不应该问什么东西是线程安全的。使用同步对象并了解。