相关疑难解决方法(0)

c# - 易失性关键字使用与锁定

我已经使用了volatile,我不确定它是否有必要.我很确定锁定在我的情况下会有点过分.阅读这个帖子(Eric Lippert评论)让我对使用volatile感到焦虑:什么时候应该在c#中使用volatile关键字?

我使用volatile是因为我的变量在多线程上下文中使用,其中可以同时访问/修改此变量,但是我可以在没有任何伤害的情况下松散添加(参见代码).

我添加"挥发性",以确保有不发生未命中对准:在另一个取可以在2通过在从另一个线程中间的写入被打破仅读取32可变的比特和其他32位.

我先前的假设(先前的陈述)是否真的可以发生?如果没有,"挥发性"使用是否仍然是必要的(选项属性修改可能在任何线程中发生).

看了2个第一个答案.我想坚持代码编写方式的事实,如果由于并发性我们错过了一个增量(想要从2个线程递增但结果仅由于并发而增加1)并不重要变量'_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)) …
Run Code Online (Sandbox Code Playgroud)

c# performance multithreading volatile dispatcher

29
推荐指数
2
解决办法
2万
查看次数

易变量

我最近接受了一家软件公司的采访,他问我以下问题:

你能告诉我在变量前添加volatile的含义是什么吗?你能解释一下为什么这很重要吗?

我的大多数编程知识都来自C,但是工作岗位是针对C#的(我想我可能会根据具体问题的需要添加这些信息)

我回答说它只是让编译器知道变量可以跨进程或线程使用,并且它不应该对该变量使用优化; 优化它可以恶化行为.简而言之,它是对编译器的警告.

然而,根据采访者的说法,反过来说,volatile关键字会警告操作系统,而不是编译器.

我对此感到有些困惑,所以我做了一些研究,实际上找到了相互矛盾的答案!一些消息来源说这是针对编译器的,还有其他针对操作系统的.

这是什么?它是否因语言而异?

c c# volatile

18
推荐指数
2
解决办法
557
查看次数

双重锁定中的记忆模型保证

我最近在Resharper网站上看到了以下帖子.这是对双重检查锁定的讨论,并具有以下代码:

public class Foo
{
    private static volatile Foo instance;
    private static readonly object padlock = new object();

    public static Foo GetValue()
    {
        if (instance == null)
        {
            lock (padlock)
            {
                if (instance == null)
                {
                    instance = new Foo();
                    instance.Init();
                }
            }
        }
        return instance;
     }

     private void Init()
     {
        ...
     }
}
Run Code Online (Sandbox Code Playgroud)

该帖子然后声称

如果我们假设Init()是用于初始化Foo状态的方法,那么由于内存模型不能保证读写顺序,上述代码可能无法按预期运行.因此,对Init()的调用实际上可能在变量实例处于一致状态之前发生.

这是我的问题:

  1. 我的理解是,.NET内存模型(至少从2.0开始)并没有要求instance被声明为volatile,因为lock它将提供一个完整的内存栅栏.是不是这样,还是我被误导了?

  2. 对于多个线程,是不是只对可观察的读/写重新排序?我的理解是,在一个线程上,副作用将是一致的顺序,并且lock就地防止任何其他线程观察到某些东西是不对的.我也在这里吗?

.net multithreading

12
推荐指数
2
解决办法
2484
查看次数

是否线程安全检查?

我有一些代码,在新线程上抛出异常,我需要在主线程上确认和处理.为了实现这一点,我通过使用保存抛出异常的字段来共享线程之间的状态.

我的问题是在检查null时是否需要使用锁,因为我在以下代码示例中进行操作?

public class MyClass
{
    readonly object _exceptionLock = new object();
    Exception _exception;

    public MyClass()
    {
        Task.Run(() =>
        {
            while (CheckIsExceptionNull())
            {
                // This conditional will return true if 'something has gone wrong'.
                if(CheckIfMyCodeHasGoneWrong())
                {
                    lock(_exceptionLock)
                    {
                        _exception = new GoneWrongException();
                    }
                }
            }
        });
    }

    bool CheckIsExceptionNull() // Is this method actually necessary?
    {
        lock (_exceptionLock)
        {
            return _exception == null;
        }
    }

    // This method gets fired periodically on the Main Thread.
    void RethrowExceptionsOnMainThread()
    { …
Run Code Online (Sandbox Code Playgroud)

c# null exception thread-safety

11
推荐指数
1
解决办法
1359
查看次数

C#bool是原子的,为什么volatile是有效的

C#中,我们知道a bool是原子的 - 那么为什么将它标记为有效volatile呢?有什么不同,什么是一个好的(甚至是实际的)用例?

bool _isPending;
Run Code Online (Sandbox Code Playgroud)

volatile bool _isPending; // Is this realistic, or insanity?
Run Code Online (Sandbox Code Playgroud)

我在这里这里做了一些阅读,我正在努力确保我完全理解两者的内部运作.我想知道什么时候使用一个与另一个相比,或者只是bool足够.

c# multithreading boolean atomic volatile

11
推荐指数
2
解决办法
1378
查看次数

C#中的寄存器

我们都知道堆栈和堆的想法,但我最近读到了第三个保存数据的选项:寄存器.

我很难找到关于这种类型的好文章,我发现的是:http://www.dotnetperls.com/method-parameter,以及C的很多内容,例如:http://igoro.com/存档/易失性-关键字在-C-存储器模型解释的/

到目前为止我唯一的实际信息:每个CPU都有自己的寄存器,可用于保存数据,以尽可能快的方式访问,例如在for循环中.

据我所见,这种注册是由CLR完成的.然后我想起了这个volatile-keyword,如果我们看一下MSDN:

volatile关键字表示某个字段可能被同时执行的多个线程修改.声明为volatile的字段不受编译器优化的约束,这些优化假定由单个线程进行访问.这可确保始终在字段中显示最新值.

那么Volatile也是如此吗?它告诉CLR不要使用CPU寄存器而是堆栈/堆,它可以被所有CPU /线程访问?

我很抱歉这个令人困惑的问题,但关于这个话题的信息确实很少.

c# clr memory-model cpu-registers

6
推荐指数
2
解决办法
2446
查看次数

除了"荣誉代码"之外,还有一个区别是使用专用的"锁定对象"并直接锁定数据吗?

我有两个线程:一个提供更新,另一个将它们写入磁盘.只有最新的更新很重要,所以我不需要PC队列.

简而言之:

  • 馈线线程将最新更新丢弃到缓冲区中,然后设置标志以指示新的更新.
  • writer线程检查该标志,如果它指示新内容,则将缓冲的更新写入磁盘并再次禁用该标志.

我目前正在使用专用锁对象来确保没有不一致,我想知道直接锁定标志和缓冲区有什么区别.我唯一知道的是,一个专用的锁对象需要信任,每个想要操纵标志和缓冲区的人都使用锁.

相关代码:

private object cacheStateLock = new object();
string textboxContents;
bool hasNewContents;

private void MainTextbox_TextChanged(object sender, TextChangedEventArgs e)
{
    lock (cacheStateLock)
    {
        textboxContents = MainTextbox.Text;
        hasNewContents = true;
    }
}

private void WriteCache() // running continually in a thread
{
    string toWrite;

    while (true)
    {
        lock (cacheStateLock)
        {
            if (!hasNewContents)
                continue;

            toWrite = textboxContents;
            hasNewContents = false;
        }

        File.WriteAllText(cacheFilePath, toWrite);
    }
}
Run Code Online (Sandbox Code Playgroud)

.net c# multithreading synchronization

6
推荐指数
1
解决办法
212
查看次数

如何通过按顺序提交load-> store重新排序?

ARM允许重新排序加载后续存储,以便以下伪代码:

// CPU 0 | // CPU 1 temp0 = x; | temp1 = y; y = 1; | x = 1;

可以导致temp0 == temp1 == 1(并且,这在实践中也是可观察到的).我无法理解这是怎么发生的; 似乎有序提交会阻止它(这是我的理解,它存在于几乎所有的OOO处理器中).我的理由是"在提交之前,负载必须具有其值,它在存储之前提交,并且在提交之前,存储的值不会对其他处理器可见."

我猜我的一个假设肯定是错的,并且必须遵循下列之一:

  • 说明不需要提交一路有序.稍后的存储可以安全地提交并在之前的加载之前变得可见,只要在存储提交核心时可以保证先前的加载(以及所有中间指令)不会触发异常,并且加载的地址是保证与商店不同.

  • 负载可以在其值已知之前提交.我不知道如何实现这一点.

  • 商店在提交之前可以显示.也许某个内存缓冲区允许将存储转发到另一个线程的加载,即使负载先前已加入?

  • 还有别的吗?

有许多假设的微体系结构特征可以解释这种行为,但我最好的是那些实际存在于现代弱有序CPU中的那些.

arm cpu-architecture memory-barriers

6
推荐指数
1
解决办法
546
查看次数

Threading.Volatile.Read(Int64)和Threading.Interlocked.Read(Int64)之间的区别?

Read(Int64).NET系统类System.Threading.Volatile和的方法有什么区别System.Threading.Interlocked

具体而言,关于(a)原子性和(b)内存排序,它们各自的保证/行为是什么。

请注意,这是关于Volatile阶级,不是volatile(小写)的关键字。


MS docs状态:

易读方法

读取字段的值。在需要它的系统上,插入一个内存屏障,以防止处理器按以下方式重新排序内存操作:如果在代码中此方法之后出现读取或写入,则处理器无法在此方法之前移动它。

...

退货 Int64

读取的值。不管处理器数量或处理器缓存状态如何,此值都是计算机中任何处理器最新写入的值。

Interlocked.Read(Int64)方法

返回作为原子操作加载的64位值。

似乎特别令人困惑的是,这些Volatile文档没有谈论原子性,并且这些Interlocked文档没有谈论排序/内存障碍。

旁注:作为参考:我更熟悉C ++原子API,其中原子操作也总是指定内存排序语义。


Pavel有用地提供的问题链接(和可传递链接)很好地解释了挥发性记忆屏障和原子无撕裂阅读的区别/正交性,但它们并没有解释这两个概念如何应用于这两个类别。

  • 是否Volatile.Read保证原子性?
  • 是否Interlocked.Read(或者,真的,任何的Interlocked功能)做出的内存为了任何保证?

c# multithreading volatile interlocked

6
推荐指数
1
解决办法
100
查看次数

不能在 C# 中编译 volatile 属性,或者是吗?

我正在尝试编译以下代码:

internal volatile bool isRunning { get; set; }    
Run Code Online (Sandbox Code Playgroud)

但是编译失败并显示错误消息,例如:“volatile 修饰符对该元素无效”。但是下面的代码会被很好地编译:

internal volatile bool _isRunning;

internal bool isRunning{
    get { return _isRunning; }
    set { _isRunning = value; }
}
Run Code Online (Sandbox Code Playgroud)

两个代码片段有什么区别??

c#

0
推荐指数
1
解决办法
2482
查看次数