0

私はさまざまな場所で見たものに基づいてタイムアウト関数を作成しましたが、それをうまくやっていないと確信しています!(しかし、それは機能しているようです。)

私はハードウェアに接続しています。動作している場合は数秒で接続しますが、そうでない場合はタイムアウトに約1分かかります。したがって、独自のタイムアウト関数を作成できれば、それを20秒に設定して、多くの時間と待機を節約できます。

タイムアウトが文字列を返すようにしようとしました:

static string CallWithTimeout(Action action, int timeoutMilliseconds)
{
    string reply = "";
    Thread threadToKill = null;
    Action wrappedAction = () =>
    {
        threadToKill = Thread.CurrentThread;
        action();
    };

    IAsyncResult result = wrappedAction.BeginInvoke(null, null);
    if (result.AsyncWaitHandle.WaitOne(timeoutMilliseconds))
    {
        reply = "Connected";
        wrappedAction.EndInvoke(result);
        return reply;
    }
    else
    {
        threadToKill.Abort();
        reply = "Error";
        return reply;            
    }      
}

それから私はそれを次のようなもので呼びます:

string replyfromreader = CallWithTimeout(connectToHardware, 20000);

ライナーはconnectToHardware1つだけなので、投稿する必要はありません。

4

2 に答える 2

1

.NET の状態に関する限り、問題ありません。リモート オブジェクトの既定の有効期間である 10 分間リソースをリークする EndInvoke() は呼び出しません。

このような場合、 Thread.Abort() を呼び出すと成功する可能性は非常に低くなります。マネージ スレッドが中止可能になるには、アラート可能な待機状態である必要があります。スレッドがネイティブ コードの奥深くに埋もれていて、デバイス ドライバーの呼び出しが完了するのを最終的に待機することは決してありません。

CLR をスレッドの中止を試行し続け、成功しない状態のままにしておくことは、特に楽しいことではありません。意図的に試したことがないため、副作用が何であるかはわかりません。ただし、コードが Abort() メソッドの呼び出しでブロックされるため、問題はまだ修正されていません。したがって、最善の方法は、スレッドを中止せずに放棄することですデバイスが無効であることを示すフラグを設定して、これを二度と行わないようにします。

デバイスが使用可能な状態になくてもプログラムを実行し続けたい場合、および問題から回復する方法を提供したい場合は、まったく異なるアプローチが必要になります。デバイス関連のコードを別のプロセスに配置する必要があります。次に、デバイスが応答しないときに Kill() を実行し、Windows に頼って破片をクリーンアップします。名前付きパイプやソケットなどの低レベルのメカニズムを使用したそのプロセスとの相互運用が最適であるため、切断からかなり簡単に回復できます。

于 2012-09-07T11:10:56.537 に答える
0

回避Thread.Abortすることは常に良い考えです。作成していないスレッドでそれを回避することは、さらに優れています。

ハードウェアが動作しておらず、タイムアウトが必要であると仮定すると、connectToHardwareそれ自体がタイムアウトするかどうかは問題ではなく、エラー/例外の詳細が必要ない場合は、Task Parallel Library (TPL) を使用できます: System.Threading.Tasks.Task:

// True => worked, False => timeout
public static bool CallWithTimeout(Action method, TimeSpan timeout) {
  Exception e;
  Task worker = Task.Factory.StartNew(method)
                    .ContineueWith(t => {
                      // Ensure any exception is observed, is no-op if no exception.
                      // Using closure to help avoid this being optimised out.
                      e = t.Exception;
                    });
  return worker.Wait(timeout);
}

(渡されたものActionが渡されたものと対話できる場合、CancellationTokenこれはよりクリーンになり、基になるメソッドがタイムアウト時にすぐに失敗する可能性があります。)

于 2012-09-07T10:51:23.300 に答える