为什么在.NET内部的Hashtable中有一个Thread.Sleep(1)?

最近我正在读.NET Hashtable的实现,遇到了一些我不明白的代码。 部分代码是:

int num3 = 0; int num4; do { num4 = this.version; bucket = bucketArray[index]; if (++num3 % 8 == 0) Thread.Sleep(1); } while (this.isWriterInProgress || num4 != this.version); 

整个代码在System.Collections.Hashtable (mscorlib版本= 4.0.0.0)的public virtual object this[object key]public virtual object this[object key]

问题是:

在那里有Thread.Sleep(1)的原因是什么?

睡眠(1)是在Windows中logging的方式来产生处理器,并允许其他线程运行。 你可以在Reference Source中find这个代码,并带有注释:

  // Our memory model guarantee if we pick up the change in bucket from another processor, // we will see the 'isWriterProgress' flag to be true or 'version' is changed in the reader. // int spinCount = 0; do { // this is violate read, following memory accesses can not be moved ahead of it. currentversion = version; b = lbuckets[bucketNumber]; // The contention between reader and writer shouldn't happen frequently. // But just in case this will burn CPU, yield the control of CPU if we spinned a few times. // 8 is just a random number I pick. if( (++spinCount) % 8 == 0 ) { Thread.Sleep(1); // 1 means we are yeilding control to all threads, including low-priority ones. } } while ( isWriterInProgress || (currentversion != version) ); 

isWriterInProgressvariables是一个易变的布尔值。 笔者在英文中遇到了一些麻烦,“违规阅读”是“易读”。 基本思想是尽量避免让步,线程上下文切换是非常昂贵的,有一些希望写作者快速完成。 如果不能平移然后显式降低以避免烧毁cpu。 这可能是今天用Spinlock写的,但是Hashtable已经很老了。 正如关于记忆模型的假设一样。

如果没有访问其他的实现代码,我只能根据你发布的内容做出有根据的猜测。

也就是说,它看起来像试图更新Hashtable中的内容,无论是在内存中还是在磁盘上,并在等待它完成时进行无限循环(如通过检查isWriterInProgress )。

如果是单核处理器,则一次只能运行一个线程。 像这样连续循环,很容易意味着其他线程没有机会运行,但是Thread.Sleep(1)给了处理器一个给作者时间的机会。 没有等待,作家线程可能永远不会有机会跑,永远不会完成。

我没有读过源代码,但看起来像是一个无锁的并发事物。 您正在尝试从哈希表中读取数据,但其他人可能正在写入数据,所以您要等到isWriterInProgress设置,并且您读取的版本没有改变。

这并不能解释为什么我们总是等待至less一次。 编辑:那是因为我们不,谢谢@Maciej指出。 当没有争用时,我们立即着手。 不过,我不知道为什么8是魔术数字,而不是4或16。