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

Tom*_* K. 9 c# multithreading asynchronous race-condition async-await

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

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

    var text = await Stream.ReadFileAsync(file);

    --readingFiles;

    return text;
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

Ste*_*ary 11

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

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

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

  • 当您调用此方法*时,没有竞争条件*.如果你多次并行调用它(在同一个实例上),那当然是不安全的.把它丢去外面. (5认同)

JMa*_*sch 0

这里可能会发生很多事情。

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

此外,由于变量周围没有内存屏障/易失性保护,因此您的线程可能会读取单独缓存的值(如 @Spo1ler 在他的帖子中提到的)

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

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