2013-05-11 2 views
5

У меня есть программа C#, которая действует как клиент и много клиентской программы, которая снова является приложением C# windows, подключается к этой программе сервера C# для чтения данных из базы данных sqlite. Для того, чтобы избежать проблем блокировки при подключении нескольких клиентов я использовал ниже код,return statement before finally

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

сервер получает вешает несколько раз и необходимо перезапустить программу сервера. Хорошо ли сделать заявление о возвращении до конца?

С уважением Sangeetha

+1

Это просто трудный способ написать инструкцию ** lock **. В противном случае бесполезно гарантировать, что только один процесс может использовать SqlLite, вместо этого вам нужно будет использовать именованный Mutex. –

ответ

4

От MSDN

Используя блок finally, вы можете очистить все ресурсы, выделенные в блоке try, и вы можете запускать код, даже если в блоке try возникает исключение. Как правило, инструкции блока finally запускаются, когда элемент управления оставляет оператор try. Передача управления может произойти в результате нормального выполнения, выполнения прерывания, продолжения, goto или return statement или распространения исключения из инструкции try.

В пределах обработанного исключения гарантируется, что соответствующий блок finally будет запущен. Однако, если исключение необработанно, выполнение блока finally зависит от того, как запускается операция отмены разблокировки. Это, в свою очередь, зависит от того, как настроен ваш компьютер. Дополнительные сведения см. В разделе Обработка необработанных исключений в среде CLR.

2

Да, это то, что finally утверждение для. Он будет выполняться после return, даже если происходит исключение

EDIT: этот простой код покажет вам, что поймать блок не требуется для окончательного блока должна быть выполнена

public Form1() 
{ 
    InitializeComponent(); 
    check(); 
} 

private string check() 
{ 
    try 
    { 
     return String.Empty; 
    } 
    finally 
    { 
     MessageBox.Show("finally"); 
    } 
} 
+1

Что? Как так??? У вас есть какие-либо материалы по этому поводу? –

+0

@ bash.d Запустите код OP в отладчике, и вы увидите :) – VladL

+0

@ bash.d определено поведение. Вы читали то, что вы опубликовали? : D "Как правило, инструкции блока finally запускаются, когда элемент управления оставляет оператор try. Передача элемента управления может произойти в результате нормального выполнения ... или return statement" – VladL

1

Поскольку у вас нет блока catch, нет гарантии, что, наконец, он будет выполнен. От MSDN - try-finally (C# Reference) и "Locks and exceptions do not mix" (Eric Lippert)

В течение перекачиваемой исключения, связанный с ним, наконец, блок гарантированно для запуска. Тем не менее, , если исключение необработанно, выполнение окончательного блока зависит от того, как выполняется операция разблокировки исключения , вызванное. Это, в свою очередь, зависит от того, как настроен ваш компьютер.

И из упомянутой ссылки (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; 
} 

Но, обратите внимание: дон 't использовать catch (Exception), чтобы скрыть исключения, это нормально, если вы повторно выбрасываете исключение. Люди также рекомендуют вам иметь один оператор return, и обычно это будет за пределами блока try.

EDIT:

Подтвержденные с программой испытаний, и от MSDN - Exceptions in Managed Threads

Начиная с .NET Framework версии 2.0, общий язык среда позволяет большинству необработанных исключений в резьб для продолжения естественно. В большинстве случаев это означает, что необработанное исключение заставляет приложение завершать работу.

Таким образом, если вы не справитесь со своим исключением, ваше приложение потерпит крах (и вам не придется беспокоиться о блокировке). Если вы справитесь с этим, ваш исходный код выполнит его, наконец, блок, и вы в порядке.

EDIT 2: Код Test обновляется, поскольку он не должным образом иллюстрируют негор наконец:

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

Is it bad practice to return from within a try catch finally block?
Это правильный способ записи Обработка исключений в C# и всегда, наконец, блок будет выполняться, это не зависит от места возвращения. Я не знаю о вашем коде, но вы должны найти свою проблему где-то в другом месте (например, если ваш код был размещен в IIS, я бы заподозрил состояние объекта Lock в разных загруженных доменах или, возможно, блокировка только для одного входящего вызова, и это происходит в базе данных или что такое Request.Clear() у вас нет блокировки?). Вы можете легко зарегистрировать состояние входящих вызовов и найти проблему.