首页 新闻 会员 周边

C#如何在多线程中同步读写一个共有属性?请大神们赐教!!!

0
悬赏园豆:5 [已解决问题] 解决于 2017-01-09 15:05

在进行多线程开发时,如何使我们的共享数据处于被保护的状态是很重要的。

使用lock关键字可以定义一段线程同步的代码语句。

例如,

        public class Printer
        {
            private object _syncRoot = new object();

            public void PrintNumbers()
            {
                lock (_syncRoot)
                {
                    // do something.
                }
            }
        }

现在我有一个共有属性Numbers,程序中的多个线程需要对它进行读写。我该如何实现同一时刻只有一个线程对其进行读写呢。请大神们赐教!!!

        public class Printer
        {
            private List<string> numbers;
            public List<string> Numbers
            {
                get { return numbers; }
                set { numbers = value; }
            }
             
        }
二线中的嗷嗷者的主页 二线中的嗷嗷者 | 初学一级 | 园豆:14
提问于:2017-01-07 22:00
< >
分享
最佳答案
1

既然是List,你可以使用ConcurrentBag<T>即可。

不过,你也可以根据需要使用

  • ConcurrentQueue
  • ConcurrentStack
  • ConcurrentBag : 一个无序的数据结构集,当不需要考虑顺序时非常有用。
  • BlockingCollection : 与经典的阻塞队列数据结构类似
  • ConcurrentDictionary

中任何一个。

收获园豆:5
ensleep | 小虾三级 |园豆:1682 | 2017-01-07 23:32

Nice job!!!给分。

二线中的嗷嗷者 | 园豆:14 (初学一级) | 2017-01-09 15:05
其他回答(1)
0

在set里加个lock(this)

吴瑞祥 | 园豆:29449 (高人七级) | 2017-01-07 23:00

set里加个lock()只是把此属性的写操作同步了,但是读操作没有同步。这样会引发状态不同步问题。比如:

假设A线程中有个循环在读取Numbers,同时B线程中有个方法在修改Numbers。这样A线程中读取的属性肯定有问题了。

支持(0) 反对(0) 二线中的嗷嗷者 | 园豆:14 (初学一级) | 2017-01-09 15:02

@二线中的嗷嗷者: 每一次的读取都不会有问题.每一次的写入也不会有问题.

其实没有场景的讨论都是耍流氓.

你还是得描述下你的场景吧.

支持(0) 反对(0) 吴瑞祥 | 园豆:29449 (高人七级) | 2017-01-09 15:18

@吴瑞祥: 

如果PrinterMonitor类的ReadNumbersAsync方法在循环读取Numbers。

碰巧此时PrinterPage类的AddNumberAsync在写Numbers,这时就有问题读取会有异常。

即便get set都加锁。在调用Numbers的get和set存取器期间,Numbers对象没有锁定,另一个线程可以获得临时值。依然没有线程安全性。

        public class Printer
        {
            private static readonly object _syncRoot = new object();

            private List<string> numbers;
            public List<string> Numbers
            {
                get { return numbers; }
                set
                {
                    lock (_syncRoot)
                    {
                        numbers = value;
                    }
                }
            }
        }

        public class PrinterMonitor
        {
            public PrinterMonitor(Printer printer)
            {
                _printer = printer;
            }

            private Printer _printer;

            private async Task ReadNumbersAsync()
            {
                await Task.Run(() =>
                {
                    _printer.Numbers.ForEach((number) =>
                    {
                        // do something with the number.
                    });
                });
            }
        }

        public class PrinterPage
        {
            public PrinterPage(Printer printer)
            {
                _printer = printer;
            }

            private Printer _printer;

            private async Task AddNumberAsync(string number)
            {
                await Task.Run(() =>
                {
                    _printer.Numbers.Add(number);
                    // do something else...
                });
            }
        }

 

支持(0) 反对(0) 二线中的嗷嗷者 | 园豆:14 (初学一级) | 2017-01-09 15:44

@吴瑞祥: 

在一个地方使用lock语句并不意味着,访问对象的其他线程都在等待。必须对每个访问共享状态的线程显式地使用同步功能。

支持(0) 反对(0) 二线中的嗷嗷者 | 园豆:14 (初学一级) | 2017-01-09 15:46

@二线中的嗷嗷者: 看了人家的才明白..你不是要做一个并发安全的类.

而是要用并发安全的类.并发安全的类就是提供一些累死 addorupdate这样的方法.

你题目中的这种情况是没法的

支持(0) 反对(0) 吴瑞祥 | 园豆:29449 (高人七级) | 2017-01-10 10:47

@吴瑞祥: 

我这种情况已经实现了,而且实现得很好,谢谢

支持(1) 反对(0) 二线中的嗷嗷者 | 园豆:14 (初学一级) | 2017-01-10 10:56

@二线中的嗷嗷者: @吴瑞祥 高手啊 解释很到位 有没案例参考下呢 设计方案 思路

支持(0) 反对(0) 亚特凯瑟琳 | 园豆:200 (初学一级) | 2019-10-28 19:22

@亚特凯瑟琳: 最佳答案中已经给出了思路啊

支持(1) 反对(0) 二线中的嗷嗷者 | 园豆:14 (初学一级) | 2019-10-29 10:52

@二线中的嗷嗷者: OK 看到了

支持(0) 反对(0) 亚特凯瑟琳 | 园豆:200 (初学一级) | 2020-02-23 09:23
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册