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

时间:2015-03-03 19:15:04

标签: c# multithreading asynchronous async-await race-condition

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

int readingFiles;
async Task<string> ReadFile (string file)
{    
    ++readingFiles;

    var text = await Stream.ReadFileAsync(file);

    --readingFiles;

    return text;
}

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

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

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

2 个答案:

答案 0 :(得分:10)

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

另见http://blogs.msdn.com/b/pfxteam/archive/2012/04/12/async-await-faq.aspx

上的评论
  

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

答案 1 :(得分:0)

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

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

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

此外,线程池可能选择在同一个线程上运行您的请求(它在其权限范围内执行此操作 - 您允许.net / windows决定何时以及如何分配线程)

尽管如此,您确实应该通过同步或互锁操作来保护对变量的访问。