我想检查一些锁定行为,我无法理解:
static void Main(string[] args)
{
for (int i = 0; i < 10; i++)
{
Task.Factory.StartNew(() =>
{
MultithreadedMethod();
});
}
Thread.Sleep(2000);
Console.WriteLine(count);
}
static int count = 0;
private static readonly int sync = 5;
public static void MultithreadedMethod()
{
if (Monitor.TryEnter(sync))
{
count++;
Monitor.Exit(sync);
}
}
我认为这应该不起作用,因为我正在对整数值进行同步。 First Boxing,然后是Unboxing,我应该得到一个System.Threading.SynchronizationLockException,因为缺少同步块根(我知道这是特定于引用类型)。 我不会欺骗自己,即使这适用于几次迭代,它也不是真的同步..所以,考虑到增量操作的非原子属性..我不会得到确定性的结果..我知道此
事实上,当我摆脱Thead.Sleep并对任务进行等待时......异常就会到位。
Task.Factory.StartNew(() =>
{
MultithreadedMethod();
}).Wait();
我认为应该抛出异常:Monitor.Exit(sync)
但是有什么能吸引它?
更新1:pic已添加。
答案 0 :(得分:6)
但是有什么能吸引它?
在Task
内隐式捕获Task
对象内引发的异常。除非您在返回的任务中访问Task.Exception
或Task.Wait/Task.Result
属性或await
,否则将吞下该异常并且您将无法看到它。这就是使用Wait
传播异常的原因,您可以在控制台中看到它。如果您使用Task.WaitAll
等待所有任务完成,也会发生同样的情况。
如果您不使用其中任何一种,您仍然可以通过注册TaskScheduler.UnobservedTaskException
来查看例外:
static void Main(string[] args)
{
TaskScheduler.UnobservedTaskException += (s,e) => Console.WriteLine(e.Exception);
for (int i = 0; i < 10; i++)
{
Task.Factory.StartNew(() =>
{
MultithreadedMethod();
});
}
Thread.Sleep(2000);
Console.WriteLine(count);
}
收率:
请注意,此代码仍然具有竞争条件,因为我们实际上并未等待任何结果,这可能不会在2秒睡眠后发生。
答案 1 :(得分:3)
当我运行你的代码时,我在输出窗口中看到:
抛出异常:&#39; System.Threading.SynchronizationLockException&#39;在ConsoleApplication5.exe中
我猜你没有捕获来自任务的异常(并且当你的IDE未被处理时你的IDE没有被设置为中断)。试试这个:
,而不是沉睡线程List<Task> tasks = new List<Task>();
for (int i = 0; i < 21000; i++)
{
tasks.Add(Task.Factory.StartNew(() =>
{
MultithreadedMethod();
}));
}
Task.WaitAll(tasks.ToArray());
WaitAll
将显示例外情况。