异步/等待代码中的竞争条件

我只是想知道下面的代码中是否出现竞争条件:

int readingFiles; async Task ReadFile (string file) { ++readingFiles; var text = await Stream.ReadFileAsync(file); --readingFiles; return text; } 

如果线程池线程执行ReadFile方法,则readFiles将由两个不同的线程访问,而readingFiles变量不受任何同步惯用法的保护。

这意味着对于执行“–readingFiles”的其他线程,readFiles的第一次更新不应该是可见的。 但是,我从未在“–readingFiles”之后看到readingFiles等于-1。 我检查同一个线程是否使用Thread.CurrentThread执行++和 – 操作。 在大多数情况下,它不是同一个线程,我仍然没有看到readingFiles为-1。

即使存在竞争条件且readingFiles不易变,为什么我不能看到这种竞争条件的影响?

这里没有竞争条件。 .NET运行时将插入适当的内存屏障。

另请参阅以下评论: http : //blogs.msdn.com/b/pfxteam/archive/2012/04/12/async-await-faq.aspx

是的,当任务排队时以及任务执行的开始/结束时,TPL包括适当的障碍,以便适当地使值可见。

这里有许多事情可以发生。

首先,你运行的是什么类型的可执行文件? 当Await触发时,它使用当前的同步上下文,因此您等待的代码可能被序列化为1个UI线程。

此外,由于变量周围没有内存屏障/波动保护,您的线程可能正在读取单独缓存的值(如@ Spo1ler在其post中所述)

此外,线程池可能选择在同一个线程上运行您的请求(这是在其权限范围内 – 您让.net / windows决定何时以及如何分配线程)

但最重要的是,您确实应该使用同步或互锁操作来保护对变量的访问。