Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/293.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# i收集、只读收集和同步。是这样吗?_C#_.net 2.0 - Fatal编程技术网

C# i收集、只读收集和同步。是这样吗?

C# i收集、只读收集和同步。是这样吗?,c#,.net-2.0,C#,.net 2.0,我有一个自定义类,它实现了ICollection,这个类是只读的,即IsReadOnly返回true(而不是使用readonly关键字),所有通常会修改集合中数据的函数抛出invalidooperationexception 现在,考虑到这样一个构造,以及在实现ICollection(特别是和朋友们)时对线程安全问题的快速浏览,我提出了这个快速而肮脏的解决方案 bool ICollection.IsSynchronised { get{ return true; } } object IColl

我有一个自定义类,它实现了
ICollection
,这个类是只读的,即
IsReadOnly
返回true(而不是使用
readonly
关键字),所有通常会修改集合中数据的函数抛出
invalidooperationexception

现在,考虑到这样一个构造,以及在实现
ICollection
(特别是和朋友们)时对线程安全问题的快速浏览,我提出了这个快速而肮脏的解决方案

bool ICollection.IsSynchronised { get{ return true; } }
object ICollection.SyncRoot { get{ return new Object(); } }

现在,给出MSDN中的示例,这不会导致不同的线程正确锁定,因为它们从
SyncRoot
获取不同的对象。鉴于这是一个只读集合,这是一个问题吗?返回
新对象()
时是否存在内存/GC问题?您在这个实现中还看到了其他问题吗?

我想问题在于,如果客户端使用同步根目录不仅锁定了您的集合,而且锁定了其他内容。假设他们缓存了集合的大小——或者“该集合的哪个子集与谓词匹配”——他们会合理地假设他们可以使用您的SyncRoot来保护您的集合及其其他成员


就我个人而言,我几乎不使用SyncRoot,但我认为总是返回相同的对象是明智的。

每次返回不同的对象似乎很奇怪。。。实际上,我很少(如果有的话)使用SyncRoot方法,因为我经常需要在多个对象之间进行同步,所以单独的对象更有意义

但是,如果数据确实是不可变的(只读),为什么不直接从IsSynchronized返回false呢

Re GC—任何此类对象通常都是短期的,并且在GEN0中收集。如果您有一个包含对象(用于锁)的字段,它将持续与集合一样长的时间,但很可能不会有任何影响

如果你需要一把锁,我很想有一把:

private readonly object lockObj = new object();
您还可以在需要时使用惰性方法仅“新建”它,如果您实际上不希望任何人请求同步锁(通过返回false到IsSynchronized),那么这就有一定的意义


另一种常见的方法是返回“this”;它使事情保持简单,但有可能与将对象用作锁用于不相关目的的其他代码发生冲突。罕见,但可能。这实际上是
[MethodImpl]
用于同步的方法。

是的,在某些情况下这是一个问题。即使集合为只读且无法更改,集合引用的对象也不是只读的。因此,如果客户端使用SyncRoot执行锁定,则在修改集合引用的对象时,它们将不具有线程安全性

我建议加上:

private readonly object syncRoot = new object();

为你们班干杯。把这个归还为SyncRoot,你就好了。

集合实际上是不可变的,没有办法修改它(当然是为了在反思中挖掘周围的东西),所以所有这些东西都应该得到保证,不应该吗?考虑到你的客户可能不知道他们得到了一个不可变的集合。显然,他们并没有试图修改它(或者他们已经得到了一个错误),但他们很可能会锁定,以确保在提供可变集合的情况下不会失败。是的,好的,他们调用Syncroot,获取一个要锁定的对象,一个其他任何人都无法获取的对象,因此锁定是无用的。但我们真的应该不必要地拖延其他线程吗?你认为这是不必要的。如果他们使用一个锁来保护多个东西,这可能是必要的。这难道不是说对象不是线程安全的吗?事实上是这样的;在我看来,关于同步集合的整个逻辑有点僵硬——很少有人希望单个操作具有线程安全性——通常需要检查一个值,然后执行其他操作。我怀疑大多数普通代码无论如何都不会检查这个属性…我认为主要原因是在foreach循环周围放置了一个锁定语句,这样当你对集合进行枚举时,如果有人修改集合,循环就不会出错。哦,我知道这个理论-它在现实中并不总是成功。。。线程/锁定很棘手,集合SyncRoot通常过于简化,提供的功能很少,而且常常被忽略(这使得它实际上毫无用处;同步要么全有要么全无)。