基本类型的锁定

6

我想检查一些锁定行为,但是我不理解这个:

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);
    }
}

我认为这应该不起作用,因为我正在对整数值进行同步。首先装箱,然后拆箱,由于缺少同步块根(我知道这仅适用于引用类型),所以我应该会得到System.Threading.SynchronizationLockException异常。即使这在几次迭代中有效,它也不是真正的同步...考虑到增量操作的非原子性质...我将无法获得确定性结果...我意识到了这一点。
实际上,当我去掉那个Thread.Sleep并在任务上放一个Wait时,异常就出现了。
Task.Factory.StartNew(() =>
 {
       MultithreadedMethod();
 }).Wait();

我认为在这里应该抛出一个异常:Monitor.Exit(sync),但是谁来捕获它呢?
更新1:已添加图片。 enter image description here

当我运行上述代码时,它确实会从“Exit”抛出异常。你确定正在捕获任务的异常吗? - Patrick Hofman
@PatrickHofman 这就是我所有的东西。只是做了这张图片。 - Olaru Mircea
2个回答

4

但是什么会捕获它呢?

Task对象中抛出的异常会被隐式地捕获在该Task中。除非您访问Task.ExceptionTask.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秒后发生。


2
当我运行您的代码时,我在输出窗口中看到:
``` Exception thrown: 'System.Threading.SynchronizationLockException' in ConsoleApplication5.exe ```
我猜测您没有捕获来自任务的异常(且您的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 会显示异常信息。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接