简体   繁体   English

我应该*始终*同步访问从多个线程使用的所有双字段/属性/变量?

[英]should I *always* synchronize access to all double field/property/variables that used from more than one thread?

Note I tend to write lock-free code so I try to avoid any types of lock where possible. 注意我倾向于编写无锁代码,所以我尽可能避免任何类型的锁。 Instead I just use while(true) loop because I have a lot of CPU power. 相反,我只是使用while(true)循环,因为我有很多CPU能力。

According to that http://msdn.microsoft.com/en-us/library/aa691278%28VS.71%29.aspx double variable update is not atomic. 根据http://msdn.microsoft.com/en-us/library/aa691278%28VS.71%29.aspx double变量更新不是原子的。

I'm concerned about two issues: 我关心两个问题:

  • if one thread modify variable of field or property and another thread read it at the same time i want to have either previous or new value, but I don't want to receive something strange. 如果一个线程修改字段或属性的变量,而另一个线程在同一时间 ,我想要么以前的或新的值读它,但我不希望收到一些奇怪的事情。 Ie if one thread changes value from 5.5 to 15.15 I want to have in another thread one of these two numbers, but not 5.15 or 15.5 or anything else. 即如果一个线程从5.5更改为15.15我希望在另一个线程中有这两个数字中的一个,但不是5.15或15.5或其他任何东西。
  • if one thread already updated value and another thread read it after that I want to receive latest, up to date, value. 如果一个线程已经更新了值,另一个线程在此之后读取它我想要接收最新的,最新的值。 I was thinking that volatile keyword can help with that but in seems it can't, because "Volatile does not guarantee freshness of a value. It prevents some optimizations, but does not guarantee thread synchronization." 我认为volatile关键字可以帮助解决这个问题,但似乎不能,因为“Volatile不能保证值的新鲜度。它会阻止一些优化,但不能保证线程同步。” as said here are c# primitive arrays volatile? 如上所述是c#原始数组volatile?

Questions: 问题:

  • Am I correct that without synchronization both of these issues may appear? 我是否正确,如果没有同步,可能会出现这两个问题?
  • If you can give me short example which proves that without synchronization it will not work - that would be nice 如果你能给我一些简短的例子,证明没有同步它就行不通 - 那会很好
  • How should I access double field or variable or property to have always real up to date value? 我应该如何访问双字段或变量或属性以始终具有真正的最新值? Will "synchronization" guarantee "freshness"? “同步”会保证“新鲜度”吗? What would be the fastest way for that? 最快的方法是什么? spinlock or something? 什么螺旋锁?

Currently I use a lot of double and decimal variables/field/properties in my program and almost everythig works fine, so I really confused because I ofthen access them from different threads without any synchronization and that just works... But now I'm thinking that probably it would be better to use float to have "built-in syncrhonization" 目前我在我的程序中使用了很多doubledecimal变量/字段/属性,几乎每个都可以正常工作,所以我真的很困惑,因为我从不同的线程访问它们而没有任何同步,这只是有效...但现在我是认为使用float进行“内置同步化”可能会更好

Yes, you need to do something. 是的,你需要做点什么。 double and decimal are not guaranteed to be atomic , so if you don't protect it you could get a torn value - ie your first bullet is entirely correct. doubledecimal 不保证是原子的 ,所以如果你不保护它,你可能会得到一个撕裂的价值 - 即你的第一颗子弹是完全正确的。

Re volatile ; volatile ; it is moot; 这是没有意义的; you are not allowed to have a volatile field that is double or decimal , so the simplest answer is: lock . 不允许有一个doubledecimalvolatile字段,所以最简单的答案是: lock

Getting double to fail is a royal PITA; double失败是皇家PITA; but here's a torn-value example featuring decimal (note the numbers of success/fail will change each iteration, even though the data is the same; this is the randomness of thread scheduling): 但这里是一个以decimal为特征的撕裂值示例(注意成功/失败的数量将改变每次迭代,即使数据相同;这是线程调度的随机性):

using System;
using System.Threading;
static class Program
{
    private static decimal shared ;
    static void Main()
    {
        Random random = new Random(12345);
        decimal[] values = new decimal[20];
        Console.WriteLine("Values:");
        for (int i = 0; i < values.Length; i++)
        {
            values[i] = (decimal)random.NextDouble();
            Console.WriteLine(values[i]);
        }
        Console.WriteLine();
        object allAtOnce = new object();
        int waiting = 10;
        shared = values[0];
        int correct = 0, fail = 0;
        for(int i = 0 ; i < 10 ; i++)
        {
            Thread thread = new Thread(() =>
            {
                lock(allAtOnce)
                {
                    if (Interlocked.Decrement(ref waiting) == 0)
                    {
                        Monitor.PulseAll(allAtOnce);
                    } else
                    {
                        Monitor.Wait(allAtOnce);
                    }
                }
                for(int j = 0 ; j < 1000 ; j++)
                {
                    for(int k = 0 ; k < values.Length ; k++)
                    {
                        Thread.MemoryBarrier();
                        var tmp = shared;
                        if(Array.IndexOf(values, tmp) < 0)
                        {
                            Console.WriteLine("Invalid value detected: " + tmp);
                            Interlocked.Increment(ref fail);
                        } else
                        {
                            Interlocked.Increment(ref correct);
                        }
                        shared = values[k];
                    }
                }
                if (Interlocked.Increment(ref waiting) == 10)
                {
                    Console.WriteLine("{0} correct, {1} fails",
                        Interlocked.CompareExchange(ref correct, 0, 0),
                        Interlocked.CompareExchange(ref fail, 0, 0));
                    Console.WriteLine("All done; press any key");
                    Console.ReadKey();
                }
            });
            thread.IsBackground = false;
            thread.Start();
        }
    }
}

The key point; 关键点; the language makes no guarantees for the atomicity of double . 语言不能保证 double的原子性。 In reality, I expect you'll be fine, but most subtle problems caused by threading are due to using "I expect" instead of "I can guarantee". 实际上,我希望你会好起来,但线程引起的大多数细微问题都是由于使用了“我期待”而不是“我可以保证”。

If you want to guarantee that a block of code will be executed and finished before another thread manipulates it, surround that block of code with a lock . 如果要保证在另一个线程操作它之前执行并完成一个代码块,请使用lock包围该代码块。

You may be lucky, and threads may never battle over using a variable, but to make sure that it never happens, making sure precautions are taken wouldn't hurt. 你可能很幸运,线程可能永远不会使用变量争夺,但为了确保它永远不会发生,确保采取预防措施不会受到伤害。

Take a look here - this might help: http://msdn.microsoft.com/en-us/library/ms173179%28v=vs.80%29.aspx 看看这里 - 这可能会有所帮助: http//msdn.microsoft.com/en-us/library/ms173179%28v=vs.80%29.aspx

a general answer would be - updates should be synchronized for all "shared" variables. 一般的答案是 - 应该为所有“共享”变量同步更新。 For exact answer need to see the code snippet. 要获得准确答案,请查看代码段。

Yes, you need to lock to be sure you get the correct result if multiple threads read/write a double at the same time. 是的,如果多个线程同时读取/写入一个double,则需要锁定以确保获得正确的结果。

Here's a failing example 这是一个失败的例子

[TestFixture]
public class DoubleTest
{
    private double theDouble;

    [Test]
    public void ShouldFailCalledParallell()
    {
        theDouble = 0;
        const int noOfTasks = 100;
        const int noOfLoopInTask = 100;
        var tasks = new Task[noOfTasks];
        for (var i = 0; i < noOfTasks; i++)
        {
            tasks[i] = new Task(() =>
                                    {
                                        for (var j = 0; j < noOfLoopInTask; j++)
                                        {
                                            theDouble++;
                                        }
                                    });
        }
        foreach (var task in tasks)
        {
            task.Start();
        }
        Task.WaitAll(tasks);
        theDouble.Should().Be.EqualTo(noOfTasks * noOfLoopInTask);
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何同步访问数据库,一次一个线程 - How to synchronize access to a database, one thread at a time 我是否需要同步对int的线程访问? - Do I need to synchronize thread access to an int? 如何从另一个线程访问 WinForms 控件,即与 GUI 线程同步? - How to access a WinForms control from another thread i.e. synchronize with the GUI thread? 使用 FluentValidation 访问验证多个字段的数据库 - Use FluentValidation to access the database validating more than one field 当使用多个表时,如何从XAML ListView获取ID? - How do I get the id from a XAML ListView when more than one table is used? 如果使用EventWaitHandel,从另一个线程读取变量时,从一个线程分配的变量是否“线程安全”? - Are variables assigned from one thread “thread-safe” when read from another thread if an EventWaitHandel is used? 为什么属性访问器中的访问修饰符应该比属性本身更具限制性? - Why access modifier in property accessors should be more restrictive than the property itself? 如何从对象列表到数组获得多个属性? - How can I get more than one property from an object list to an array? 我应该为数据库表使用多个视图模型吗? - Should I be using more than one viewmodel for a database table? 从Datagrid中的多个列写入Access中的多个列 - Writing to more than one Column in Access from more than one Column in Datagrid
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM