【发布时间】:2022-01-11 02:47:00
【问题描述】:
编辑
我发现Building Async Coordination Primitives, Part 1: AsyncManualResetEvent 可能与我的主题有关。
在 TaskCompletionSource 的情况下,这意味着同步延续可以作为调用 {Try}Set* 的一部分发生,这意味着在我们的 AsyncManualResetEvent 示例中,这些延续可以作为 Set 方法的一部分执行。根据您的需求(以及在所有同步延续执行时,Set 的调用者是否可以接受可能运行时间更长的 Set 调用),这可能是您想要的,也可能不是。
非常感谢所有的答案,感谢您的知识和耐心!
原始问题
我知道Task.Run 在线程池线程上运行,线程可以重新进入。但是我从来不知道当两个任务都活着时,它们可以在同一个线程上运行!
我的问题是:设计合理吗?这是否意味着异步方法中的lock 没有意义(或者说,如果我想要一个不允许重入的方法,lock 不能在异步方法块中被信任)?
代码:
namespace TaskHijacking
{
class Program
{
static TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
static object methodLock = new object();
static void MethodNotAllowReetrance(string callerName)
{
lock(methodLock)
{
Console.WriteLine($"Enter MethodNotAllowReetrance, caller: {callerName}, on thread: {Thread.CurrentThread.ManagedThreadId}");
if (callerName == "task1")
{
tcs.SetException(new Exception("Terminate tcs"));
}
Thread.Sleep(1000);
Console.WriteLine($"Exit MethodNotAllowReetrance, caller: {callerName}, on thread: {Thread.CurrentThread.ManagedThreadId}");
}
}
static void Main(string[] args)
{
var task1 = Task.Run(async () =>
{
await Task.Delay(1000);
MethodNotAllowReetrance("task1");
});
var task2 = Task.Run(async () =>
{
try
{
await tcs.Task; // await here until task SetException on tcs
}
catch
{
// Omit the exception
}
MethodNotAllowReetrance("task2");
});
Task.WaitAll(task1, task2);
Console.ReadKey();
}
}
}
输出:
Enter MethodNotAllowReetrance, caller: task1, on thread: 6
Enter MethodNotAllowReetrance, caller: task2, on thread: 6
Exit MethodNotAllowReetrance, caller: task2, on thread: 6
Exit MethodNotAllowReetrance, caller: task1, on thread: 6
线程6的控制流程如图:
【问题讨论】:
-
“我知道任务在线程上运行” -- 不,一般任务are not running on threads。如果您想要一个从头到尾在单个线程上运行的
Task,它必须是delegate-based task,而不是从async方法创建的promise 式任务。 -
@Tomingsun 好吧,
Task.Run确实 在 ThreadPool 线程上运行(the documentation 这么说),但你无法控制 which线程。 -
Tomingsun 异步编程的重点是通过不阻塞线程来有效利用线程。拥有
ThreadPool的全部意义在于重用线程,而不是为每个需要线程的微小操作启动一个新线程。将这两个概念结合在一起,是的,你会看到很多“劫持”发生。 -
Tomingsun 多线程很难。实际上,
lock语句的可重入性是您必须经常注意的陷阱之一,以便编写行为正确的多线程代码。
标签: c# asynchronous locking task