2012-01-26 103 views
17

私はこの例外について別の記事を見つけましたが、私の場合はどれも例外ではありません。ここ は、ソースコードである:オブジェクト同期メソッドが非同期コードブロックから呼び出されました。 Mutex.Release()の例外

class Program 
{ 

    private static Mutex mutex; 
    private static bool mutexIsLocked = false; 
    static void Main(string[] args) 
    { 

     ICrmService crmService = 
      new ArmenianSoftware.Crm.Common.CrmServiceWrapper(GetCrmService("Armsoft", "crmserver")); 
     //Lock mutex for concurrent access to workflow 
     mutex = new Mutex(true, "ArmenianSoftware.Crm.Common.FilterCtiCallLogActivity"); 
     mutexIsLocked = true; 

     //Create object for updating filtered cti call log 
     ArmenianSoftware.Crm.Common.FilterCtiCallLog filterCtiCallLog = 
      new ArmenianSoftware.Crm.Common.FilterCtiCallLog(crmService); 
     //Bind events 
     filterCtiCallLog.CtiCallsRetrieved += new EventHandler<ArmenianSoftware.Crm.Common.CtiCallsRetrievedEventArgs>(filterCtiCallLog_CtiCallsRetrieved); 

     //Execute filter 
     try 
     { 
      filterCtiCallLog.CreateFilteredCtiCallLogSync(); 
     } 
     catch (Exception ex) 
     { 
      throw ex; 
     } 
     finally 
     { 
      if (mutexIsLocked) 
      { 
       mutexIsLocked = false; 
       mutex.ReleaseMutex(); 
      } 
     } 
    } 

    static void filterCtiCallLog_CtiCallsRetrieved(object sender, 
     ArmenianSoftware.Crm.Common.CtiCallsRetrievedEventArgs e) 
    { 
     tryasasas 
     { 
      if (mutexIsLocked) 
      { 
       mutexIsLocked = false; 
       mutex.ReleaseMutex(); 
      } 
     } 
     catch (Exception ex) 
     { 
      throw ex; 
     } 
    } 
} 

filterCtiCallLog.CreateFilteredCtiCallLogSync();機能は、サーバーへのリクエストを実行し、CtiCallsRetrieveイベントそのうちの1つは、いくつかのイベントを発生させます。このイベントが発生すると、ミューテックスを解放する必要があります。しかし、mutex.Release()関数の例外を呼び出すと例外がスローされます。 CreateFilteredCtiCallLogSyncは同期して動作します。何が問題ですか?

答えて

33

ミューテックスが所有されていることを示しているのは重大な間違いです。 boolをスレッドセーフにしていません。間違った同期オブジェクトを使用しているため、このピクルに入っています。 mutexはスレッド親和性を持ち、mutexの所有者はスレッドです。それを取得したスレッドは、ReleaseMutex()を呼び出すスレッドでもなければなりません。だからあなたのコードは爆弾です。

ここではイベントが必要です。ここではAutoResetEventを使用してください。それをメインスレッドで作成し、ワーカーのSet()を呼び出し、メインスレッドのWaitOne()を呼び出して、ワーカーがそのジョブを完了するのを待ちます。それを後で処分する。また、スレッドを使用してジョブを実行し、メインスレッドがその完了を待つことは生産的ではないことにも注意してください。あなたは、メインスレッドに仕事をさせることもできます。

スレッドセーフではないオブジェクトへのアクセスを保護するためにこれを実際に行っている場合は、のロックステートメントを使用します。

+0

あなたが正しいです - コールバックを設定するスレッドがメインスレッドであることを忘れました:( –

+0

AutoResetEventは素晴らしいです!ありがとうHans。 –

2

私はこれを1〜2回しか持っていませんでしたが、私は自分が所有していなかったミューテックスをリリースしようとしました。

イベントは、mutexが取得された同じスレッドで発生していますか? filterCtiCallLog.CreateFilteredCtiCallLogSync()がブロッキングコールであると言いますが、おそらくイベントを発生させるワーカースレッドが生成されていますか?

2

フラグを使用してカーネルシンクロオブジェクトの状態を監視しようとすると、機能しません。これらのシンクロコールを使用するポイントは、明示的なチェックなしで正しく動作することです。フラグを設定すると間欠的な問題が発生します。なぜなら、フラグをチェックしてからアクションを実行するまでの間に、フラグが不適切に変更される可能性があるからです。

mutexは、それを取得した脅威によってのみリリースされます。コールバックが別のスレッド(CreateFilteredCtiCallLogSync()またはカーネルスレッドプールの内部)によって呼び出された場合、リリースは失敗します。

何をしようとしているのかはっきりしません。おそらく、CreateFilteredCtiCallLogSync()へのアクセスとインスタンスが再利用できるコールバックフラグをシリアル化する必要がありますか?もしそうなら、代わりにセマフォを使うことができます。それを1つのユニットに渡し、開始時にそれを待ち、コールバックで解放します。

時にはコールバックが呼び出されないことがあり、try/finally/releaseという問題がありますか?もしそうなら、コールバックが非同期的で、セットアップスレッドがその機能を出た後に別のスレッドによって呼び出されるかもしれないならば、この方法は少しばかげているようです。

5

私はこの問題を発見しました。 filterCtiCallLogクラスについての最初のいくつかのこと。私は非同期と同期の両方で動作するように設計しました。最初は非同期実行のためのコードを書いています。子作業スレッドから親にイベントをトリガーする方法が必要でした。作業状態を報告しました。このため私はAsyncOperationクラスを使用しており、それはpostメソッドです。 CtiCallsRetrievedイベントをトリガするコード部分は次のとおりです。

public class FilterCtiCallLog 
{ 
    private int RequestCount = 0; 
    private AsyncOperation createCallsAsync = null; 
    private SendOrPostCallback ctiCallsRetrievedPost; 
    public void CreateFilteredCtiCallLogSync() 
    { 
     createCallsAsync = AsyncOperationManager.CreateOperation(null); 
     ctiCallsRetrievedPost = new SendOrPostCallback(CtiCallsRetrievedPost); 
     CreateFilteredCtiCallLog(); 
    } 

    private void CreateFilteredCtiCallLog() 
    { 
     int count=0; 
     //do the job 
     //............ 
     //........... 
     //Raise the event 
     createCallsAsync.Post(CtiCallsRetrievedPost, new CtiCallsRetrievedEventArgs(count)); 
     //........... 
     //........... 
    } 

    public event EventHandler<CtiCallsRetrievedEventArgs> CtiCallsRetrieved; 

    private void CtiCallsRetrievedPost(object state) 
    { 
     CtiCallsRetrievedEventArgs args = state as CtiCallsRetrievedEventArgs; 
     if (CtiCallsRetrieved != null) 
      CtiCallsRetrieved(this, args); 
    } 
} 

ご覧のとおり、コードは同期して実行されています。ここでの問題はAsyncOperation.Post()メソッドにあります。私は、それがメインスレッドで呼び出された場合、イベントをトリガーするだけで親スレッドにポストするのではないと推測しました。しかしそれは事実ではなかった。どのように動作しているのかわかりませんが、CreateFilteredCtiCallLogが同期または非同期と呼ばれるかどうかを確認するためにコードを変更しました。そして、非同期呼び出しの場合は、AsyncOperation.Postメソッドを使用しました。そうでない場合は、nullでない場合は、単にEventHandlerをトリガーしました。ここに修正コードがあります

public class FilterCtiCallLog 
{ 
    private int RequestCount = 0; 
    private AsyncOperation createCallsAsync = null; 
    private SendOrPostCallback ctiCallsRetrievedPost; 
    public void CreateFilteredCtiCallLogSync() 
    { 
     createCallsAsync = AsyncOperationManager.CreateOperation(null); 
     ctiCallsRetrievedPost = new SendOrPostCallback(CtiCallsRetrievedPost); 
     CreateFilteredCtiCallLog(false); 
    } 

    private void CreateFilteredCtiCallLog(bool isAsync) 
    { 
     int count=0; 
     //do the job 
     //............ 
     //........... 
     //Raise the event 
     RaiseEvent(CtiCallsRetrievedPost, new CtiCallsRetrievedEventArgs(count),isAsync); 
     //........... 
     //........... 
    } 

    public event EventHandler<CtiCallsRetrievedEventArgs> CtiCallsRetrieved; 

    private void RaiseEvent(SendOrPostCallback callback, object state, bool isAsync) 
    { 
     if (isAsync) 
      createCallsAsync.Post(callback, state); 
     else 
      callback(state); 
    } 

    private void CtiCallsRetrievedPost(object state) 
    { 
     CtiCallsRetrievedEventArgs args = state as CtiCallsRetrievedEventArgs; 
     if (CtiCallsRetrieved != null) 
      CtiCallsRetrieved(this, args); 
    } 
} 

ありがとうございました!

たぶん
0

ない最も意味のあるエラーメッセージ、私は、これは以下のようにいくつかのサードパーティ製のコードで起こる見てきた、

object obj = new object(); 
lock (obj) 
{ 
    //do something 

    Monitor.Exit(obj);//obj released 

}//exception happens here, when trying to release obj 
0

私は非同期に呼び出して、あなたがモニターを使用してコードをロックしたときにこれが起こる見てきましたこれは、ロック(オブジェクト)を使用するとコンパイラエラーが発生しますが、monitor.enter(オブジェクト)とMonitor.Exist(オブジェクト)の間では、コンパイラは不平を言っていません。

関連する問題