SerialPort を使用してハードウェアと接続する必要がある C# マルチスレッド アプリケーションがあります。
プログラムはほとんどがコマンド応答シーケンスですが、内部エラーが原因でハードウェアが未承諾の「RESET」メッセージを送信する可能性があり、その時点でソフトウェアは特定の値を設定する一連のコマンドを送信してプログラムを再初期化する必要があります。
複数のスレッド (スレッドプールから) が TakeSampleNow() を実行しようとする可能性があります
public class ALComm
{
private readonly AutoLoaderManager _manager;
private readonly AutoResetEvent dataArrived = new AutoResetEvent(false);
private SerialPort _alPort;
private string _alResponse;
.... Code to init _alPort and attach datareceived event etc
public void TakeSampleNow()
{
if (Monitor.TryEnter(_alPort, 1000)) //let's wait a second
{
_manager.MessageList.Enqueue("Try sampling");
try
{
Send("Command1");
string response = Receive();
switch(response)
{
case "X": blah blah..
case "Y": blah blah..
}
Send("Command2");
string response = Receive();
while(response != "OK")
{
Send("Command3");
string response = Receive();
Send("Command2");
string response = Receive();
}
}
finally
{
Console.WriteLine("Releasing port");
//Thread.CurrentThread.Priority = ThreadPriority.Normal;
Monitor.Exit(_alPort);
}
else
{
_manager.MessageList.Enqueue("Port is busy!!!");
}
}
public string Receive()
{
string inString = null;
dataArrived.WaitOne(1000);
inString = _alResponse;
return inString;
}
private void AlPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
_alResponse = _alPort.ReadLine();
//if (_alResponse.ToUpper().Contains("RESET"))
//{
// _alState = AlState.Reset;
// TryInitialize();
//}
dataArrived.Set();
}
private void TryInitialize()
{
Monitor.Enter(_alPort); //lock so other threads do not access samplenow during initialization
try
{
string response;
Console.WriteLine("Initializing ... The AutoLoader");
_alPort.DiscardInBuffer();
Send("CommandX");
response = Receive();
--- blah blah
_alResponse = "";
}
finally
{
Monitor.Exit(_alPort);
}
}
datareceived イベントで応答を確認し、TryInitialize() でロックを待機し、TakeSampleNow の他のスレッドがロックを解放するのを待つことができます。_alResponse に「RESET」が含まれているかどうか、およびメソッドから返されるかどうかを各応答で確認する必要があります。 . それはそれをより複雑にします。
どうすればこれを改善できるかについての提案。ステート マシンになる可能性はあると思いますが、概念化することはできません。