2015-10-13 49 views
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,因为缺少同步块根(我知道这是特定于引用类型)。 我不会愚弄自己,即使这只是为了迭代而工作,它并不是真正的同步..所以,考虑到增量操作的非原子属性..我不会得到确定性的结果..我知道这个的。

事实上,当我摆脱那个Thead.Sleep,并把任务等待..异常到位。

Task.Factory.StartNew(() => 
{ 
     MultithreadedMethod(); 
}).Wait(); 

我觉得异常应该在这里抛出:Monitor.Exit(sync)

但什么抓住了吗?

更新1:图片已添加。

enter image description here

+0

当我运行上面的代码时,它会从'Exit'引发异常。当然你从任务中捕获异常? –

+0

@PatrickHofman这就是我拥有的一切。刚拍了照片。 –

回答

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

产量:

Unobserved task exception

注意此代码仍然有赛车中因为我们实际上并没有等待任何结果出现,这可能在2秒钟的睡眠后不会发生。

+1

@thumbmunkeys即使在修复之后(感谢您指出了这一点),我们仍然存在竞争条件,所以它不会“真的”重要,但仍然会通过编辑来说清楚。 –

2

当我运行你的代码,我看到在我的输出窗口:

抛出异常: 'System.Threading.SynchronizationLockException' 在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将显示异常。