在缺少布尔条件变量的波动性的情况下,为什么该程序不会进入无限循环? [英] Why this program does not go into infinite loop in absence of volatility of a boolean condition variable?

查看:87
本文介绍了在缺少布尔条件变量的波动性的情况下,为什么该程序不会进入无限循环?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想了解何时确切需要将变量声明为volatile.为此,我写了一个小程序,并期望由于缺少条件变量的易变性而陷入无限循环.它没有进入无限循环,没有volatile关键字也可以正常工作.

I wanted to understand on when exactly I need to declare a variable as volatile. For that I wrote a small program and was expecting it to go into infinite loop because of missing volatility of a condition variable. It did not went into infinite loop and worked fine without volatile keyword.

两个问题:

  1. 我应该在下面的代码清单中进行哪些更改,以便绝对需要使用volatile?

  1. What should I change in the below code listing - so that it absolutely requires use of volatile?

C#编译器是否足够聪明,可以将变量视为易失性-如果它看到正在从其他线程访问该变量?

Is C# compiler smart enough to treat a variable as volatile - if it sees that a variable is being accessed from a different thread?

以上内容引发了我更多的问题:)

The above triggered more questions to me :)

a.挥发只是提示吗?

a. Is volatile just a hint?

b.在多线程上下文中,什么时候应该将变量声明为volatile?

b. When should I declare a variable as volatile in context of multithreading?

c.对于线程安全类,是否应将所有成员变量声明为volatile?那是矫kill过正吗?

c. Should all member variables be declared volatile for a thread safe class? Is that overkill?

代码清单(重点是波动性和线程安全性)

Code Listing (Volatility and not thread safety is the focus):

class Program
{
    static void Main(string[] args)
    {
        VolatileDemo demo = new VolatileDemo();
        demo.Start();

        Console.WriteLine("Completed");
        Console.Read();
    }
}

    public class VolatileDemo
    {
        public VolatileDemo()
        {
        }

        public void Start()
        {
            var thread = new Thread(() =>
            {
                Thread.Sleep(5000);
                stop = true;
            });

            thread.Start();

            while (stop == false)
                Console.WriteLine("Waiting For Stop Event");
        }

        private bool stop = false;
    }

谢谢.

推荐答案

尝试像这样重写它:

    public void Start()
    {
        var thread = new Thread(() =>
        {
            Thread.Sleep(5000);
            stop = true;
        });

        thread.Start();

        bool unused = false;
        while (stop == false)
            unused = !unused; // fake work to prevent optimization
    }

并确保您以发布模式而不是调试模式运行.在发布模式下,将应用优化,这实际上会导致在没有volatile的情况下代码失败.

And make sure you are running in Release mode and not Debug mode. In Release mode optimizations are applied which actually cause the code to fail in the absence of volatile.

编辑:有关volatile的一些信息:

我们都知道,程序生命周期中涉及两个不同的实体,它们可以以变量缓存和/或指令重新排序的形式应用优化:编译器和CPU.

We all know that there are two distinct entities involved in a program lifecycle that can apply optimizations in the form of variable caching and/or instruction reordering: the compiler and the CPU.

这意味着您编写代码的方式与实际执行方式甚至可能有很大的差异,因为指令可能相对于彼此重新排序,或者读取可能会被缓存在编译器认为是速度提高".

This means that there may be even a large difference between how you wrote your code and how it actually gets executed, as instructions may be reordered with respect to eachother, or reads may be cached in what the compiler perceives as being an "improvement in speed".

在大多数情况下,这是件好事,但有时(尤其是在多线程上下文中)可能会引起麻烦,如本例所示.为了使程序员能够手动阻止此类优化,引入了内存隔离栅,这是一种特殊的指令,其作用是防止相对于隔离栅本身对指令(仅读取,仅写入或同时对两者)进行重新排序,并防止值的无效化.在CPU缓存中,因此每次都需要重新读取它们(这是我们在上述方案中想要的).

Most of the times this is good, but sometimes (especially in the multithreading context) it can cause trouble as seen in this example. To allow the programmer to manually prevent such optimizations, memory fences were introduced, which are special instructions whose role is to prevent both reordering of instructions (just reads, just writes or both) with respect to the fence itself and also force the invalidation of values in CPU caches, such that they need to be re-read every time (which is what we want in the scenario above).

尽管您可以通过Thread.MemoryBarrier()指定影响所有变量的完整栅栏,但是如果只需要影响一个变量,这几乎总是一个矫kill过正的做法.因此,要使单个变量始终在线程中保持最新状态,可以使用volatile仅为该变量引入读/写防护.

Although you can specify a full fence affecting all variables through Thread.MemoryBarrier(), it's almost always an overkill if you need only one variable to be affected. Thus, for a single variable to be always up-to-date across threads, you can use volatile to introduce read/write fences for that variable only.

这篇关于在缺少布尔条件变量的波动性的情况下,为什么该程序不会进入无限循环?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆