2009-12-17 32 views
9

Asenkron modda açılan bir System.IO.Pipe.NamedPipeServerStream açıldığında WaitHandle'ın ideal olması için daha fazla veriye sahip olduğunda bildirim almanın bir yolunu bulmalıyım. Böyle bir tutamaç elde etmek için sadece BeginRead() kullanamıyorum çünkü boruya yazmak istediğim başka bir iş parçacığı tarafından sinyallenebiliyor olabilirim - bu yüzden borudaki kilidi serbest bırakmak ve yazımın tamamlanmasını beklemek zorundayım. ve NamedPipeServerStream bir CancelAsync yöntemine sahip değildir. Ayrıca, BeginRead() 'i çağırmayı denedim, daha sonra iş parçacığının sinyal alması durumunda borunun üzerindeki win32 işlevini iptal etmeyi denedim, ama bunun ideal bir çözüm olduğunu düşünmüyorum çünkü eğer veriler gelmekte ve işlenmekte olduğu gibi CancelIO ise bırakılmam gerekirse - Bu verileri hala saklamak istiyorum, ancak yazının ardından daha sonra işlemek istiyorum. PeekNamedPipe'nın yararlı olabileceğinden şüpheleniyorum ama onunla sürekli olarak yeni veriler bulmaktan kaçınmak istiyorum. Yukarıdaki metin burada, biraz belirsizdir i yapabilmek istediğim şey kabaca olduğunu likley halinde Adlandırılmış Borular - Eşzamansız Peeking

...

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; 
    } 
} 

cevap

9

Tamam, bunu kodumdan çıkardım, umarım tüm uygulama mantığını sildim. Buradaki fikir, ReadFile ile sıfır uzunluklu bir okuma yapmayı denemek ve lpOverlapped.EventHandle'ın (okuma tamamlandığında tetiklenen) ve başka bir iş parçacığı boruya yazmak istediğinde ayarlanan WaitHandle'ın her ikisini beklemenizdir. Okuma, bir yazı dizisi nedeniyle kesilecekse, sıfır uzunluklu okumayı iptal etmek için CancelIoEx kullanın.

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); 
+0

+1: Verileri gerçekte hiç bir veri okumadan yazıldığı zaman bir sinyal almanın bir yolu olarak örtüşen G/Ç ile 0 bayt okumaların kullanılması çok yararlıdır ve belgelerde açıkça belirtilmemiştir. –

1

MSDN aracılığıyla bakınca, herhangi bir mekanizma görmüyorum istediğini yapmak için. En hızlı çözüm, PeekNamedPipe'a erişmek için interop kullanmaktır. interop'u kullanmak istemiyorsanız, özel bir sınıfın içindeki boruyu soyutlayabilir ve soyutlama içinde eş işlevi sağlayabilirsiniz. Soyutlama tüm sinyallemeyi ele alacak ve okumayı ve boruya yazmayı koordine etmelidir. Açıkçası, önemsiz bir görev değil.

Diğer bir alternatif, eğer mümkünse sizin durumunuzda, bu soyutlamadan oldukça fazla olan WCF'yi kullanmaktır.

+0

Oh vay, bir cevap! Teşekkürler :) Aslında bu yaşları çözdüm, ama şimdi çözümü çözeceğim. –