Domanda

Ho bisogno di trovare un modo per essere avvisati quando uno System.IO.Pipe.NamedPipeServerStream aperto in modalità asincrona ha più dati disponibili per la lettura su un it- WaitHandle sarebbe l'ideale. Non posso usare semplicemente BeginRead () per ottenere un tale manico, perché è possibile che io possa essere segnalato da un altro thread che vuole scrivere alla palina quindi devo rilasciare il blocco sul tubo e attendere che la scrittura sia completa, e NamedPipeServerStream non ha una metodo CancelAsync. Ho anche provato a chiamare BeginRead (), quindi chiamare la funzione Win32 CancelIO sul tubo se il filo viene segnalata, ma non che questa è una soluzione ideale perché se CancelIO è chiamato come dati arriva e in lavorazione, lo farà essere dropped- ho ancora desidera mantenere questi dati, ma elaborarlo in un secondo momento, dopo la scrittura. Ho il sospetto che la funzione Win32 PeekNamedPipe potrebbe essere utile, ma mi piacerebbe evitare di dover continuamente il polling per i nuovi dati con esso.

Nel caso in likley che il testo di cui sopra è un po 'poco chiaro, ecco più o meno quello che mi piacerebbe essere in grado di fare ...

NamedPipeServerStream pipe;
ManualResetEvent WriteFlag;
//initialise pipe
lock (pipe)
{
    //I wish this method existed
    WaitHandle NewDataHandle = pipe.GetDataAvailableWaithandle();
    Waithandle[] BreakConditions = new Waithandle[2];
    BreakConditions[0] = NewDataHandle;
    BreakConditions[1] = WriteFlag;
    int breakcode = WaitHandle.WaitAny(BreakConditions);
    switch (breakcode)
    {
        case 0:
            //do a read on the pipe
            break;
        case 1:
            //break so that we release the lock on the pipe
            break;
     }
}
È stato utile?

Soluzione

Ok, così ho strappato questo fuori del mio codice, si spera ho cancellato tutta la roba logica dell'applicazione. L'idea è che si tenta una lunghezza zero letto con ReadFile e aspettare sia sul lpOverlapped.EventHandle (licenziato quando la lettura completa) e un set WaitHandle quando un altro thread vuole scrivere al tubo. Se la lettura è interrotta a causa di un filo scrittura, utilizzare CancelIoEx per annullare la lettura di lunghezza zero.

NativeOverlapped lpOverlapped;
ManualResetEvent DataReadyHandle = new ManualResetEvent(false);
lpOverlapped.InternalHigh = IntPtr.Zero;
lpOverlapped.InternalLow = IntPtr.Zero;
lpOverlapped.OffsetHigh = 0;
lpOverlapped.OffsetLow = 0;
lpOverlapped.EventHandle = DataReadyHandle.SafeWaitHandle.DangerousGetHandle();
IntPtr x = Marshal.AllocHGlobal(1); //for some reason, ReadFile doesnt like passing NULL in as a buffer
bool rval = ReadFile(SerialPipe.SafePipeHandle, x, 0, IntPtr.Zero,
   ref lpOverlapped);
int BreakCause;
if (!rval) //operation is completing asynchronously
{
   if (GetLastError() != 997) //ERROR_IO_PENDING, which is in fact good
      throw new IOException();
   //So, we have a list of conditions we are waiting for
   WaitHandle[] BreakConditions = new WaitHandle[3];
   //We might get some input to read from the serial port...
   BreakConditions[0] = DataReadyHandle;
    //we might get told to yield the lock so that CPU can write...
   BreakConditions[1] = WriteRequiredSignal;
   //or we might get told that this thread has become expendable
   BreakConditions[2] = ThreadKillSignal;
   BreakCause = WaitHandle.WaitAny(BreakConditions, timeout);
}
else //operation completed synchronously; there is data available
{
   BreakCause = 0; //jump into the reading code in the switch below
}
switch (BreakCause)
{
   case 0:
      //serial port input
      byte[] Buffer = new byte[AttemptReadSize];
      int BRead = SerialPipe.Read(Buffer, 0, AttemptReadSize);
      //do something with your bytes.
      break;
   case 1:
      //asked to yield
      //first kill that read operation
      CancelIoEx(SerialPipe.SafePipeHandle, ref lpOverlapped);
      //should hand over the pipe mutex and wait to be told to tkae it back
      System.Threading.Monitor.Exit(SerialPipeLock);
      WriteRequiredSignal.Reset();
      WriteCompleteSignal.WaitOne();
      WriteCompleteSignal.Reset();
      System.Threading.Monitor.Enter(SerialPipeLock);
      break;
   case 2:
      //asked to die
      //we are the ones responsible for cleaning up the pipe
      CancelIoEx(SerialPipe.SafePipeHandle, ref lpOverlapped);
      //finally block will clean up the pipe and the mutex
      return; //quit the thread
}
Marshal.FreeHGlobal(x);

Altri suggerimenti

Guardando attraverso MSDN, non vedo alcun meccanismo per fare quello che vuoi. La soluzione più rapida è porbably utilizzare interoperabilità per accedere PeekNamedPipe. Se non si desidera utilizzare interop, si può astrarre il tubo all'interno di una classe personalizzata e forniscono le funzionalità sbirciatina all'interno della astrazione. L'astrazione sarebbe gestire tutte le segnalazioni e coordinarsi lettura e scrittura al tubo. Ovviamente, non è un compito banale.

Un'altra alternativa, se possibile, nella tua situazione, è quello di considerare di usare WCF che è praticamente che l'astrazione.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top