Are C# structs thread safe?

前端 未结 6 2011
感情败类
感情败类 2020-12-03 12:22

Is a C# struct thread-safe?

For example if there is a:

struct Data
{
    int _number;
    public int Number { get { return _number; } set { _number =         


        
相关标签:
6条回答
  • 2020-12-03 13:02

    No, structures in .NET are not intrinsically thread-safe.

    However, the copy-by-value semantics that structures have great relevance to this converation.

    If you are passing your structures around and assigning them in some way to variables or pass-by-value parameters (no ref or out keywords) then a copy is being used.

    Of course, this means that any changes made to the copy are not reflected in the original structure, but it's something to be aware of when passing them around.

    If you are accessing the structure directly in a manner that doesn't involve copy-by-value semantics (e.g. accessing a static field which is the type of the structure, and as Marc Gravel points out in his answer, there are many other ways) across multiple threads, then you have to take into account the thread-safety of the instance.

    0 讨论(0)
  • 2020-12-03 13:03

    Well - best practice is that structs should always (except in a few very specific scenarios, and even then at risk) be immutable. And immutable data is always thread safe. So if you followed best practice and made this:

    struct Data
    {
        readonly int _number;
        public int Number { get { return _number; } }
    
        public Data(int number) { _number = number; }
    }
    

    then yes; that is thread-safe. In all other cases the answer is "probably not".

    Note also that atomicity rules apply, so even a single read or update to DadData.TheData cannot be assumed to be thread-safe, even with an immutable struct. You could (especially for oversized structs) have one thread reading the struct while another thread re-writes it; without synchronization bad things will happen (eventually).

    0 讨论(0)
  • 2020-12-03 13:03

    Different threads' direct reads and writes of different members of a mutable struct will not interfere with each other. Different threads' access to the same member via Interlocked methods will behave according to the semantics of those methods. These facts may allow mutable structs to allow thread-safe behavior.

    Mutable storage locations holding structs that offer no means of mutation except outright replacement offer no thread-safety whatsoever, except that in cases where a struct holds either a single 32-bit integer or a single object reference, an attempt to read a such a (single-item) struct storage location at the same time as it is being written is guaranteed to read entirely old data or entirely new data. Note that it is not possible to use any of the Interlocked methods with immutable structs--even structs which contain only a single integer or object reference.

    0 讨论(0)
  • 2020-12-03 13:12

    No, they are not. I created very simple app to see if 10/10 producer/consumer threads are accessing same struct variable. And eventually you will see Debugger.Break(); will be hit. Bank balance should never go under 0 value.

    namespace StructThreadSafe
    {
        class Program
        {
            struct BankBalance
            {
                public decimal Balance { get; set; }
            }
    
            static void Main(string[] args)
            {
                BankBalance bankBalance = new BankBalance();
                bankBalance.Balance = 100;
                List<Task> allTasks = new List<Task>();
                for (int q = 0; q < 10; q++)
                {
                    Task producer = new Task(() =>
                    {
                        for (int i = 0; i < 1000; i++)
                        {
                            if (bankBalance.Balance < 0)
                            {
                                if (Debugger.IsAttached)
                                {
                                    Debugger.Break();
                                }   
                            }
                            bankBalance.Balance += 5;
                            Console.WriteLine("++Current Balance: " + bankBalance.Balance);
                            System.Threading.Thread.Sleep(100);
                        }
                    });
                    allTasks.Add(producer);
                }
                for (int w = 0; w < 10; w++)
                {
                    Task consumer = new Task(() =>
                    {
                        for (int i = 0; i < 1000; i++)
                        {
                            if (bankBalance.Balance < 0)
                            {
                                if (Debugger.IsAttached)
                                {
                                    Debugger.Break();
                                }
                            }
                            if (bankBalance.Balance > 15)
                            {
                                bankBalance.Balance -= 15;
                                Console.WriteLine("--Current Balance: " + bankBalance.Balance);
                            }
                            else
                            {
                                Console.WriteLine("**Current Balance below minimum: " + bankBalance.Balance);
                            }
                            System.Threading.Thread.Sleep(100);
                        }
                    });
                    allTasks.Add(consumer);
                }
                allTasks.ForEach(p => p.Start());
                Task.WaitAll(allTasks.ToArray());
    
            }
        }
    }
    
    0 讨论(0)
  • 2020-12-03 13:16

    A struct is not any more thread-safe than an ordinary field or variable. If you have at least one thread modifying it, and at least one more thread touching it in any way at the same time, you may end up with unexpected/undefined behaviour.

    Also, mutable structs are code smells. Is there some particular reason you need it to be a struct instead of a class? Do you need value-type semantics for this data?

    0 讨论(0)
  • 2020-12-03 13:16

    No. Why would it be thread-safe? It's just data. It doesn't become thread-safe by magic.

    0 讨论(0)
提交回复
热议问题