誰も私に次の問題の良い解決策を教えてもらえますか?非同期リソースへのアクセスをシリアル化する方法は?
私が取り組んでいるアプリケーションは、TCPを介して他のシステムで動作するソフトウェアと通信する必要があります。そのシステムに送信する要求の中には、完了までに長時間(最大15秒)かかる場合があります。私のアプリケーションで
私は、リモート・システムと通信サービスにアクセスすることができ、メインUIスレッドを含むスレッドの数を、持っています。すべてのスレッドがアクセスするサービスのインスタンスは1つだけです。
一度に1つのリクエストしか処理できないようにする必要があります。つまり、シリアル化する必要があります。それ以外の場合は、TCP通信で問題が発生します。
未遂ソリューションこれまで
次のように当初、私は、各「コマンド」メソッドを保護するための静的オブジェクトで)(ロックを使用してみました:
lock (_cmdLock)
{
SetPosition(position);
}
私はその時々それたがリモートシステムとTCP通信にタイムアウトがあっても、ロックを解放しません。さらに、同じスレッド(例えば、ユーザがボタンをダブルクリックした場合)から2つのコールが入った場合、ロックを過ぎてしまいます。ロックを再度読み取った後、同じスレッドがロックを待たないことがわかります。
次に、AutoResetEventsを使用して、一度に1つの通話のみを許可しようとしました。しかし、ロックがなければ、複数のスレッドでは動作しません。以下は、私は、コマンド要求のキューを実装しようとしていない私は(呼び出し元のスレッドからの)コマンドを送信し、(自身のスレッド上でバックグラウンドで実行されている)コマンド要求を処理するために使用されるコード
private static AutoResetEvent _cmdProcessorReadyEvent = new AutoResetEvent(false);
private static AutoResetEvent _resultAvailableEvent = new AutoResetEvent(false);
private static AutoResetEvent _sendCommandEvent = new AutoResetEvent(false);
// This method is called to send each command and can run on different threads
private bool SendCommand(Command cmd)
{
// Wait for processor thread to become ready for next cmd
if (_cmdProcessorReadyEvent.WaitOne(_timeoutSec + 500))
{
lock (_sendCmdLock)
{
_currentCommand = cmd;
}
// Tell the processor thread that there is a command present
_sendCommandEvent.Set();
// Wait for a result from the processor thread
if (!_resultAvailableEvent.WaitOne(_timeoutSec + 500))
_lastCommandResult.Timeout = true;
}
return _lastCommandResult.Success;
}
// This method runs in a background thread while the app is running
private void ProcessCommand()
{
try
{
do
{
// Indicate that we are ready to process another commnad
_cmdProcessorReadyEvent.Set();
_sendCommandEvent.WaitOne();
lock (_sendCmdLock)
{
_lastCommandResult = new BaseResponse(false, false, "No Command");
RunCOMCommand(_currentCommand);
}
_resultAvailableEvent.Set();
} while (_processCommands);
}
catch (Exception ex)
{
_lastCommandResult.Success = false;
_lastCommandResult.Timeout = false;
_lastCommandResult.LastError = ex.Message;
}
}
です呼び出しコードはすべてが同期することを期待しています。つまり、次のコマンドを送信する前に前のコマンドが完了していなければなりません。
追加の背景
リモートシステム上で動作するソフトウェアは、サードパーティの製品であり、私はそれへのアクセスを持っていない、統合されたXYテーブルとレーザーマーキングマシンを制御するために使用されます。
私は実際にレガシーVB6 DLLを使用してレーザーと通信しています。コマンドをフォーマットして応答を処理するためのすべてのコードが含まれています。このVB6 DLLは、通信にWinSockコントロールを使用します。
レーザーを制御します!サメの頭に付いていますか?あなたはミニですか? ;) –