2009-12-17 14 views
9

मुझे अधिसूचित होने का एक तरीका ढूंढने की आवश्यकता है जब एक सिस्टम.आईओ.पीपी.NamedPipeServerStream एसिंक्रोनस मोड में खोला गया है, उस पर पढ़ने के लिए अधिक डेटा उपलब्ध है- वेटहैंडल आदर्श होगा। मैं इस तरह के हैंडल प्राप्त करने के लिए बस BeginRead() का उपयोग नहीं कर सकता क्योंकि यह संभव है कि मुझे किसी अन्य थ्रेड द्वारा संकेत दिया जा सके जो पाइप को लिखना चाहता है- इसलिए मुझे पाइप पर लॉक जारी करना है और लेखन को पूरा करने की प्रतीक्षा है, और NamedPipeServerStream में CancelAsync विधि नहीं है। मैंने BeginRead() को कॉल करने का भी प्रयास किया, फिर पाइप पर Win32 फ़ंक्शन CancelIO को कॉल करने पर हस्ताक्षर किए जाने पर, लेकिन मुझे नहीं लगता कि यह एक आदर्श समाधान है क्योंकि अगर रद्द करने के लिए डेटा को आ रहा है और डेटा संसाधित हो रहा है, तो यह होगा गिरा दिया जाना चाहिए- मैं अभी भी इस डेटा को रखना चाहता हूं, लेकिन लिखने के बाद बाद में इसे संसाधित करता हूं। मुझे संदेह है कि Win32 फ़ंक्शन PeekNamedPipe उपयोगी हो सकता है लेकिन मैं इसके साथ नए डेटा के लिए निरंतर मतदान करने से बचना चाहता हूं।नामित पाइप्स - असिंक्रोनस पेकिंग

likley घटना है कि ऊपर पाठ थोड़ा स्पष्ट नहीं है, यहाँ मोटे तौर पर मैं ऐसा करने में सक्षम होना चाहते हैं क्या में ...

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

उत्तर

9

ठीक है, इसलिए मैंने इसे अपने कोड से बाहर निकाल दिया, उम्मीद है कि मैंने सभी एप्लिकेशन लॉजिक सामान हटा दिए हैं। विचार यह है कि आप रीडफाइल के साथ शून्य-लंबाई पढ़ने की कोशिश करते हैं और दोनों lpOverlapped.EventHandle (जब पूरा हो जाता है तब निकाल दिया जाता है) और एक प्रतीक्षा थंडल सेट होता है जब कोई अन्य थ्रेड पाइप पर लिखना चाहता है। यदि किसी लेखन धागे के कारण पढ़ने को बाधित किया जाना है, तो शून्य-लंबाई पढ़ने को रद्द करने के लिए CancelIoEx का उपयोग करें।

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: 0-बाइट का उपयोग ओवरलैप्ड I/O के साथ सिग्नल प्राप्त करने के तरीके के रूप में पढ़ता है जब डेटा किसी भी डेटा को पढ़ने के बिना लिखा जाता है, तो बहुत उपयोगी होता है, और दस्तावेज़ीकरण में स्पष्ट नहीं होता है। –

1

MSDN के माध्यम से देख रहे हैं, मैं किसी भी तंत्र नहीं दिख रहा है जो करना चाहते हैं उसे करने के लिए। PeekNamedPipe तक पहुंचने के लिए इंटरपॉप का उपयोग करने के लिए सबसे तेज़ समाधान संभवतः है। यदि आप interop का उपयोग नहीं करना चाहते हैं, तो आप कस्टम क्लास के अंदर पाइप को अमूर्त कर सकते हैं और अबास्ट्रक्शन के भीतर चरम कार्यक्षमता प्रदान कर सकते हैं। अमूर्तता सभी सिग्नलिंग को संभालेगी और पाइप को पढ़ने और लिखने का समन्वय करना होगा। जाहिर है, एक छोटा काम नहीं है।

आपकी स्थिति में यदि संभव हो तो एक और विकल्प, डब्ल्यूसीएफ का उपयोग करना है जो कि अमूर्तता है।

+0

ओह वाह, एक उत्तर! धन्यवाद :) मैंने वास्तव में इस उम्र को हल किया है हालांकि, मैं अब समाधान को रखूंगा। –

संबंधित मुद्दे