5

クライアントとして機能するac#プログラムがあり、これもac#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);
}

サーバーが何度かハングし、サーバー プログラムを再起動する必要があります。最終的に前に return ステートメントを作成するのは良い習慣ですか?

よろしくサンギータ

4

4 に答える 4

4

MSDNから

finally ブロックを使用すると、try ブロックで割り当てられたリソースをクリーンアップでき、try ブロックで例外が発生した場合でもコードを実行できます。通常、finally ブロックのステートメントは、制御が try ステートメントを離れたときに実行されます。制御の移動は、通常の実行、break、continue、goto、return ステートメントの実行、または try ステートメントからの例外の伝播の結果として発生する可能性があります。

処理された例外内で、関連する finally ブロックが実行されることが保証されます。ただし、例外が未処理の場合、finally ブロックの実行は、例外アンワインド操作がどのようにトリガーされるかに依存します。これは、コンピューターのセットアップ方法によって異なります。詳細については、「CLR での未処理の例外処理」を参照してください。

于 2013-05-11T10:27:10.283 に答える
2

はい、それがfinallyステートメントの目的です。return例外が発生しても、 の後に実行されます

EDIT:この単純なコードは、最後にブロックを実行するためにcatchブロックが必要ないことを示します

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

private string check()
{
    try
    {
        return String.Empty;
    }
    finally
    {
        MessageBox.Show("finally");
    }
}
于 2013-05-11T10:25:32.623 に答える
1

catch ブロックがないため、finally が実行される保証はありません。MSDNから- try-finally (C# リファレンス)および「ロックと例外が混在しない」(Eric Lippert)

処理された例外内で、関連する finally ブロックが実行されることが保証されます。ただし、例外が未処理の場合、finally ブロックの実行は、例外のアンワインド操作がどのようにトリガーされるかに依存します。これは、コンピューターのセットアップ方法によって異なります。

そして、言及されているリンクから(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 以降では、共通言語ランタイムにより、スレッド内の未処理の例外のほとんどが自然に処理されます。ほとんどの場合、これは未処理の例外が原因でアプリケーションが終了することを意味します。

そのため、例外を処理しないと、アプリケーションがクラッシュします (ロックについて心配する必要はありません)。それを処理すると、元のコードが実行され、最終的にブロックされ、問題ありません。

EDIT 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);
        }
    }
}
于 2013-05-11T11:08:17.010 に答える