【发布时间】:2021-07-02 11:55:12
【问题描述】:
我看到各地的人都建议尽可能使用ConfigureAwait(false),这是图书馆作者必须使用的,等等。
但是由于ConfigureAwait(false) 的延续可以在线程池中的任何线程上运行,那么如何安全地防止多个线程访问库中的相同状态?
假设您的库有以下 API:
async Task FooAsync()
{
// Do something
//barAsync and saveToFileAsync are private methods.
await barAsync().ConfigureAwait(false);
// counter is a private field
counter++;
await saveToFileAsync().ConfigureAwait(false);
// Do other things
}
如果 UI 线程一直调用此 FooAsync(例如,由于用户按下按钮),此代码不会损坏 counter 的值并保存文件吗?由于可能正在执行多个线程?
除了不修改状态的最简单的情况外,我发现很难在没有线程安全的情况下使用 ConfigureAwait(false)。
更新
我可能不清楚,但在我们的团队中,我们决定使用单线程。因此,从下面的答案来看,我们似乎不能使用ConfigureAwait(false),因为它引入了并行的可能性,需要使用锁等来控制。
【问题讨论】:
-
你不能。不知道还能说什么。即使在没有使用 ConfigureAwait 的情况下,您的代码也不是线程安全的,因为您无法保证调用者一开始就在 UI 线程上。
-
那时你可能需要考虑锁定
-
只要代码不是上下文感知的,建议使用 ConfigureAwait(false)。一个示例是 asp .NET 应用程序中的 HttpContext。您不能从请求线程以外的线程访问它。
-
@Lasse 你是对的。大多数人不是为线程安全而设计的,他们认为只有一个线程在运行,这是默认的。普通的 async/await 很适合这个,但是,当你添加 ConfigureAwait(false) 时,你需要线程安全,但是在我访问的大多数问题中似乎没有人解决这个问题,它给人的印象是 ConfigureAwait(false)是一个简单的更改,但不,它有后果并可能导致损坏状态。
-
Most people don't design for thread-safety我不认为这是真的。大多数 good 库都是线程安全的,因为存在的小全局状态被锁定。除非特别说明(例如Concurrent...类),否则不期望单个对象应该是线程安全的。例如,List<T>作为单个对象不是线程安全的。SqlConnection不是线程安全的,而是使用内部连接池。
标签: c# multithreading asynchronous .net-core thread-safety