سؤال

أحتاج إلى إيجاد طريقة لإخطارها عند فتح System.IO.Pipe.NamedPipeServerstream في الوضع غير المتزامن يحتوي على المزيد من البيانات المتاحة للقراءة على ذلك - ستكون Waithandle مثالية. لا أستطيع ببساطة استخدام المبتدئين () للحصول على مثل هذا المقبض لأنه من الممكن أن يتم الإشارة إلى مؤشر ترابط آخر يريد الكتابة إلى الأنابيب، لذلك يجب علي إطلاق قفل على الأنبوب وانتظر الكتابة لتكون كاملة، و namedpipeserverstream لا تملك طريقة clindasync. حاولت أيضا الاتصال بالدعوة ()، ثم استدعاء الوظيفة Win32 Inclishio على الأنبوب إذا تمت الإشارة إلى الخيط، لكنني لا أعتقد أن هذا حلا مثاليا لأنه إذا تم استدعاء "إلغاء" تماما "كما وصلت البيانات ومعالجتها" انخفض - ما زلت أتمنى الاحتفاظ بهذه البيانات، لكنها تعالجها في وقت لاحق، بعد الكتابة. أظن أن وظيفة 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;
     }
}
هل كانت مفيدة؟

المحلول

حسنا، لذلك أنا فقط انفصلت عن هذا من التعليمات البرمجية، ونأمل أن أحذف جميع الاشياء منطق التطبيق. هذه الفكرة هي أن تحاول الطول الصفر قراءة مع ReadFile وانتظر كلا LpoverLapped.eventhandle (أطلقت عند اكتمال القراءة) ومجموعة waithandle عندما يريد مؤشر ترابط آخر الكتابة إلى الأنبوب. إذا تم مقاطعة القراءة بسبب خيط الكتابة، استخدم IncliCioEx لإلغاء قراءة الطول الصفر.

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

نصائح أخرى

بالنظر إلى MSDN، لا أرى أي آلية لفعل ما تريد. يحظى حلا بشكل ملحوظ باستخدام Interop للوصول إليه PeekNamedPipe. وبعد إذا كنت لا ترغب في استخدام interop, ، يمكنك مجردة الأنابيب داخل فئة مخصصة وتزويد الوظيفة النقطية داخل التجريد. سوف تتعامل التجريد التعامل مع جميع الإشارات وتؤمل لتنسيق القراءة والكتابة إلى الأنبوب. من الواضح، وليس مهمة تافهة.

هناك بديل آخر، إن أمكن في وضعك، هو أن ننظر في استخدام WCF الذي هو إلى حد كبير هذا التجريد.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top