我有一个c#程序充当客户端和许多客户端程序,这也是c#windows应用程序连接到这个c#服务器程序以从sqlite数据库读取数据。为了避免在连接多个客户端时出现锁定问题,我使用了下面的代码,
System.Threading.Monitor.Enter(Lock);
try
{
filter.Execute();//get data from database
Request.Clear();
return filter.XML;//create xml and return to client
}
finally
{
System.Threading.Monitor.Exit(Lock);
}
服务器挂起一些时间,需要重启服务器程序。 在最后做出回复声明是否是一个很好的实践?
此致 桑杰塔
答案 0 :(得分:4)
来自MSDN
通过使用finally块,您可以清除try块中分配的所有资源,即使try块中发生异常,您也可以运行代码。通常,当控件离开try语句时,finally块的语句会运行。控制权的转移可能是由于正常执行,执行break,continue,goto或return语句,或者是try语句中的异常传播而发生的。
在处理的异常中,保证运行关联的finally块。但是,如果未处理异常,则finally块的执行取决于如何触发异常展开操作。反过来,这取决于您的计算机的设置方式。有关更多信息,请参阅CLR中的未处理异常处理。
答案 1 :(得分:2)
是的,这是finally
声明的用途。它将在return
之后执行,即使发生异常
编辑: 这个简单的代码将向您显示,最终块执行时不需要catch块
public Form1()
{
InitializeComponent();
check();
}
private string check()
{
try
{
return String.Empty;
}
finally
{
MessageBox.Show("finally");
}
}
答案 2 :(得分:1)
由于没有捕获块,因此无法保证最终将被执行。来自MSDN - try-finally (C# Reference)和"Locks and exceptions do not mix" (Eric Lippert)
在处理的异常中,保证关联的finally块 要运行。但是,如果异常未处理,则执行 finally块取决于异常展开操作的方式 触发即可。反过来,这取决于您的计算机的设置方式。
然后从后面提到的链接(Unhandled Exception Processing In The CLR)中有各种考虑因素,这可能意味着你最终得到一个终止的线程。我真的不知道这是否会让你锁定锁对象。
如果你想确保:
然后做:
TheXmlType xml = null;
Monitor.Enter(Lock);
bool inLock = true;
try {
...
xml = filter.Xml; // put this here in case it throws an exception
inLock = false; // set this here in case monitor.exit is to
// throw an exception so we don't do the same all over again in the catch block
Monitor.Exit(Lock);
return xml; // this is fine here, but i would normally put it outside my try
}
catch (Exception) {
if (inLock) Monitor.Exit(Lock);
throw;
}
但是,请注意:不要使用catch (Exception)
隐藏异常,只有在重新抛出异常时才可以。人们还建议您使用单个return
语句,通常这将在您的try块之外。
修改强>
通过测试程序和MSDN - Exceptions in Managed Threads
确认从.NET Framework 2.0版开始,这是一种通用语言 运行时允许线程中的大多数未处理的异常继续 自然。在大多数情况下,这意味着未处理的异常 导致应用程序终止。
因此,如果您不处理异常,您的应用程序将崩溃(您不必担心锁定)。如果你确实处理了它,那么你原来的代码会执行它的最终阻止你就可以了。
编辑2:测试代码已更新,因为它最终没有正确说明非射击:
class Program
{
static void Main(string[] args) {
Program p =new Program();
p.Start();
Console.WriteLine("done, press enter to finish");
Console.ReadLine();
}
private readonly object SyncRoot = new object();
ManualResetEvent mre = new ManualResetEvent(false);
private void Start() {
/*
* The application will run the thread, which throws an exception
* While Windows kicks in to deal with it and terminate the app, we still get
* a couple of "Failed to lock" messages
* */
Thread t1 = new Thread(SetLockAndTerminate);
t1.Start();
mre.WaitOne();
for (int i = 0; i < 10; i++) {
if (!Monitor.TryEnter(this.SyncRoot, 1000)) {
Console.WriteLine("Failed to lock");
}
else {
Console.WriteLine("lock succeeded");
return;
}
}
Console.WriteLine("FINALLY NOT CALLED");
}
public int CauseAnOverflow(int i)
{
return CauseAnOverflow(i + 1);
}
public void SetLockAndTerminate() {
Monitor.Enter(this.SyncRoot);
Console.WriteLine("Entered");
try {
mre.Set();
CauseAnOverflow(1); // Cause a stack overflow, prevents finally firing
}
finally {
Console.WriteLine("Exiting");
Monitor.Exit(this.SyncRoot);
}
}
}
答案 3 :(得分:0)
Is it bad practice to return from within a try catch finally block?
这是在c#中编写异常处理的正确方法,并且总是会执行块,它不依赖于返回的位置。
我不知道您的代码,但您应该在其他地方找到您的问题(例如,如果您的代码在IIS中托管,我会怀疑Lock对象在不同的加载域中的状态,或者锁定只是一个来电,它发生了在数据库或什么是Request.Clear()你没有锁块?)。您可以轻松记录来电状态并找到问题。