C#:从锁定块调用事件

我经常听说在调用事件监听器之前解锁所有锁是个好主意,以避免死锁。 但是,由于lock {}块可以由C#中的同一个线程重入,是否可以从锁定块调用事件,或者我是否需要复制相关状态数据并在锁定块外调用事件?

如果没有,请举例说明从lock {}块中调用事件是否有问题。

谢谢

我不记得曾经需要在lock声明中提出事件。 但不难想象事情会发生严重变化。

当您举起活动时,您将执行推迟到可能不是您自己的代码。 如果您正在编写某些将由其他人使用的库或框架,则尤其如此。 在事件处理程序内部,您完全无法控制发生的情况。 事件处理程序可以启动一个全新的线程并在返回之前等待该线程完成(即Join() )。 如果那个新线程调用某个函数锁定了与你的lock ,宾果游戏相同的变量。 僵局。

但除此之外,最佳做法是尽量减少locklock的时间,以减少lock的“阻塞点”方面。 如果你在lock内举起一个事件,所有的赌注都会被取消。

问题不在于事件处理程序可能会尝试调用您已经拥有的锁,问题是事件处理程序可能尝试获取某些其他锁(可能阻塞并设置死锁),或者事件处理程序可能会像数据库查询一样启动一些长时间运行的任务(让你的锁无法访问其他线程,直到完成)。 一般规则是你应该尽可能短的时间锁定。

将线程与您无法控制的事件处理程序混合肯定会让您感到麻烦。 我目前遇到了一些麻烦,因为我从串口的接收线程中提出了一个事件。 某些事件处理程序代码决定阻塞并等待,直到从串行端口收到另一条消息。 这将是一个漫长的等待,因为你只是阻止了一个只接收线程! 我甚至不能生气,因为我写了两段代码(相隔一年,所以我有时间忘记细节)。

是的,从持有的锁中调用事件不会被认为是好的设计。 主要是因为锁定部分有一个转换,如果是抛出错误或有问题,锁定不一定会被释放。

通常,您希望最小化锁定时间以防止持有锁定太长时间(导致延迟),并且还要减少锁定时可能出现代码失败的可能性。