2011-04-05 63 views
2

c#中是否存在类似于lock {}的构造,但在从事件处理程序调用时工作,即在处理后续事件之前等待代码块完成。C#从事件中锁定

我遇到的问题是锁只阻止其他线程获取对象上的锁,但是如果同一线程上的事件处理程序被调用,锁块内代码的执行将被中断,并且在返回执行原始代码之前处理新事件。

object DoStuffLock = new object(); 

public void DoStuff() 
{ 
    lock (DoStuffLock) 
    { 
     // Do stuff that we don't want to be interrupted, 
     // but because it is called from an event handler 
     // it still can be interrupted despite the lock 
    } 
} 

目前我周围像这样的问题,工作(但很难理想):

object DoStuffLock = new object(); 

// this gets called from an event, and therefore can be interrupted, 
// locking does not help, so launch separate thread 
public void DoStuff() 
{ 
    var x = new Thread(DoStuffInternal); 
    x.Start(); 
} 

private void DoStuffInternal() 
{ 
    lock (DoStuffLock) 
    { 
     // Do stuff that we don't want to be interrupted 
    } 
} 
+0

线程不能被事件“中断”。你还没有诊断出真正的问题。 – 2011-04-05 20:06:08

+0

确实 - 你是对的 - 我没有诊断出真正的问题。 – 2011-04-05 20:47:57

回答

3

我遇到的问题是,锁定{}只是阻止其他从获得线程锁定对象,但是如果同一线程上的事件处理程序被调用

这真的不会发生。如果您的线程正在执行,则在同一线程上不会发生事件 - 必须在不同的线程中引发该事件。

这就是说,在任何情况下,你的“第二种方法”在许多方面都是优越的。有一个隐含的假设,事件处理程序将很快返回。 “阻塞”事件处理程序通常是设计不好的标志,并且可能会导致问题,特别是因为事件发布者不会期望事件被阻止。

+0

有问题的事件由FileSystemWatcher触发,并且DoStuff()中的代码非常快速地返回。尽管如此,如果FileSystemWatcher以非常快的速度连续触发多个事件(并且经常这样做),DoStuff()中的代码会被中断以处理新事件。 – 2011-04-05 19:42:54

+0

@Mthethew:你可以在没有单独线程的情况下执行锁定。 FileSystemWatcher在线程池线程上引发事件 - 所以你的锁在那里工作的很好。它永远不会在同一个线程中引发它,因为你的代码正在执行。因此,它永远不会中断你的代码 - 它可能同时运行2个副本(这使得调试器看起来像是中断,但检查线程窗口..)。如果这不可取,则方法中的锁将保护它而不需要单独启动线程。 – 2011-04-05 19:45:16

+0

你当然是正确的 - 问题存在于其他地方 - 并且在单独的线程中运行锁定代码似乎是通过延迟执行来“解决”问题 - 感谢坚持认为我错了,并让我重新检查了所有内容时间。 – 2011-04-05 20:46:42

0

想想锁定代码,而不是对象。

使用相同的锁对象锁定无法同时输入的代码段。

此外,锁不停止中断,它们只是同时停止从2个线程访问同一段代码。

0

UI事件都是从同一个线程调用的。锁旨在保护多线程。锁专门设计为允许同一个线程多次调用同一个锁,否则会发生死锁。

我认为你的第二个解决方案是正确的。如果你有一段代码必须在一个块中执行,那么你在一个新的线程上执行它。

0

在Windows等操作系统中,您无法对事件处理的顺序作出任何假设。只有使用实时操作系统才能完成此操作。

你可以做你的情况是你可以增加你的线程优先级。这应该给你的线程更多的时间(相对于其他线程)。有关.net中的线程优先级的更多信息,请访问:http://msdn.microsoft.com/en-us/library/system.threading.threadpriority.aspx