J'essaie d'utiliser la propriété .BaseStream du .NET2.0 SerialPort pour effectuer des lectures et des écritures asynchrones (BeginWrite/EndWrite, BeginRead/EndRead). J'ai un certain succès dans ce domaine, mais après un certain temps, je remarque (en utilisant Process Explorer) une augmentation très progressive des poignées que l'application utilise, et parfois un thread supplémentaire, qui augmente également le nombre de poignées.Comment utiliser correctement le port série .NET2.0 .BaseStream pour l'opération asynchrone
Le taux de changement de contexte augmente également chaque fois qu'un nouveau thread apparaît.
L'application envoie constamment 3 octets à un dispositif PLC, et obtient quelque 800 octets en retour, et ce, à une vitesse de transmission de 57600.
Le delta initial cDébranchez (encore une fois, à partir de l'explorateur de processus) est autour de 2500, ce qui semble très élevé de toute façon. Chaque fois qu'un nouveau thread apparaît, cette valeur augmente et la charge du processeur augmente en conséquence. J'espère que quelqu'un pourrait avoir fait quelque chose de similaire, et peut m'aider, ou même dire 'Au nom de Dieu, ne le faites pas de cette façon.'
Dans le code ci-dessous, 'this._stream' est obtenu à partir de SerialPort.BaseStream, et CommsResponse est une classe que j'utilise comme objet d'état IAsyncresult.
Ce code est commun à une connexion TCP que je fais comme alternative à l'utilisation du port série, (j'ai une classe de base CommsChannel, avec un canal série et TCP dérivé) et il n'a aucun de ces problèmes. Je suis raisonnablement optimiste qu'il n'y a rien de mal avec la classe CommsResponse.
Commentaires reçus avec reconnaissance.
/// <summary>
/// Write byte data to the channel.
/// </summary>
/// <param name="bytes">The byte array to write.</param>
private void Write(byte[] bytes)
{
try
{
// Write the data to the port asynchronously.
this._stream.BeginWrite(bytes, 0, bytes.Length, new AsyncCallback(this.WriteCallback), null);
}
catch (IOException ex)
{
// Do stuff.
}
catch (ObjectDisposedException ex)
{
// Do stuff.
}
}
/// <summary>
/// Asynchronous write callback operation.
/// </summary>
private void WriteCallback(IAsyncResult ar)
{
bool writeSuccess = false;
try
{
this._stream.EndWrite(ar);
writeSuccess = true;
}
catch (IOException ex)
{
// Do stuff.
}
// If the write operation completed sucessfully, start the read process.
if (writeSuccess) { this.Read(); }
}
/// <summary>
/// Read byte data from the channel.
/// </summary>
private void Read()
{
try
{
// Create new comms response state object.
CommsResponse response = new CommsResponse();
// Begin the asynchronous read process to get response.
this._stream.BeginRead(this._readBuffer, 0, this._readBuffer.Length, new AsyncCallback(this.ReadCallback), response);
}
catch (IOException ex)
{
// Do stuff.
}
catch (ObjectDisposedException ex)
{
// Do stuff.
}
}
/// <summary>
/// Asynchronous read callback operation.
/// </summary>
private void ReadCallback(IAsyncResult ar)
{
// Retrieve the comms response object.
CommsResponse response = (CommsResponse)ar.AsyncState;
try
{
// Call EndRead to complete call made by BeginRead.
// At this point, new data will be in this._readbuffer.
int numBytesRead = this._stream.EndRead(ar);
if (numBytesRead > 0)
{
// Create byte array to hold newly received bytes.
byte[] rcvdBytes = new byte[numBytesRead];
// Copy received bytes from read buffer to temp byte array
Buffer.BlockCopy(this._readBuffer, 0, rcvdBytes, 0, numBytesRead);
// Append received bytes to the response data byte list.
response.AppendBytes(rcvdBytes);
// Check received bytes for a correct response.
CheckResult result = response.CheckBytes();
switch (result)
{
case CheckResult.Incomplete: // Correct response not yet received.
if (!this._cancelComm)
{
this._stream.BeginRead(this._readBuffer, 0, this._readBuffer.Length,
new AsyncCallback(this.ReadCallback), response);
}
break;
case CheckResult.Correct: // Raise event if complete response received.
this.OnCommResponseEvent(response);
break;
case CheckResult.Invalid: // Incorrect response
// Do stuff.
break;
default: // Unknown response
// Do stuff.
break;
}
}
else
{
// Do stuff.
}
}
catch (IOException ex)
{
// Do stuff.
}
catch (ObjectDisposedException ex)
{
// Do stuff.
}
}
Merci pour votre réponse. Bonne suggestion concernant la création des rappels. Je l'ai essayé, mais le taux de commutation handle/thread/contexte augmente encore, bien qu'il semble augmenter à un rythme plus lent, donc une amélioration. – Andy