المنفذ التسلسلي والمناولة الأخطاء أثناء عمليات الإدخال / الإخراج المتداخلة
-
19-09-2019 - |
سؤال
لقد قمت بعمل الاتصالات التسلسلية مؤخرا حتى أعدت فئة كونها واجهة بسيطة لجميع وظائف واجهة برمجة تطبيقات Windows المسؤولة عن القراءة والكتابة وما إلى ذلك. يتم التعامل مع جميع عمليات الإدخال / الإخراج داخل هذه الفئة بطريقة غير متزاملة.
قبل أن أذهب إلى سؤالي، اسمحوا لي أن أظهر لك كيف أكتب وقراءة البيانات من المنفذ التسلسلي (هذه هي وظيفة القراءة فقط، لأن هيكل الكتابة هو نفسه بالضبط لذلك لا توجد نقطة في تقديم كل منهما) وبعد
function TSerialPort.Read(var pBuffer; const lBufferSize: Cardinal): Cardinal;
var
lOverlapped: OVERLAPPED;
lLastError: Cardinal;
lEvent: TEvent;
begin
lEvent := TEvent.Create(nil, True, False, '');
try
FillChar(lOverlapped, SizeOf(lOverlapped), 0);
lOverlapped.hEvent := lEvent.Handle;
if not ReadFile(FSerialPortHandle, pBuffer, lBufferSize, Result, @lOverlapped) then
begin
lLastError := GetLastError;
if (lLastError <> ERROR_IO_PENDING) and (lLastError <> ERROR_SUCCESS) then
raise Exception.Create(SysErrorMessage(lLastError));
case lEvent.WaitFor(INFINITE) of
wrSignaled:
if not GetOverlappedResult(FSerialPortHandle, lOverlapped, Result, False) then
raise Exception.Create(SysErrorMessage(GetLastError));
wrError:
begin
lLastError := lEvent.LastError;
//this is a call to Windows.CancelIo(FSerialPortHandle);
if Self.CancelIO() then
lEvent.WaitFor(INFINITE);
raise Exception.Create(SysErrorMessage(lLastError));
end;
end;
end;
finally
FreeAndNil(lEvent);
end;
end;
قبل أن تسألني لماذا أفتح المنفذ التسلسلي للعمليات المتداخلة بينما تنتظر هذه الوظيفة عملية القراءة حتى النهاية، إليك تفسيري - فقط عند فتح المنفذ التسلسلي بهذه الطريقة يمكنني تحديد طريقة تنتظر الوقت الانتظار () في انتظار الأحداث. إذا فتحت المنفذ للعمليات غير المتداخلة، فستمنح waitcommevent () حتى يظهر حدثا على المنفذ التسلسلي الذي لا يمكن أن يحدث دائما مما يؤدي إلى حظر مؤشر ترابط الاتصال إلى الأبد.
ومع ذلك، دعونا نركز على وظيفة القراءة أعلاه ().
1) أولا وقبل كل شيء، أنتظر دون تحديد أي مهلة زمنية للحدث. هل هناك احتمال أن يمنع الخيط الحالي إلى الأبد لسبب ما بسبب ذلك؟ لا أعرف ما إذا كان بإمكاني أن أكون متأكدا بنسبة 100٪ من أن الحدث سوف يتم تعيينه في وقت أقرب أو في وقت لاحق بواسطة مؤشر الترابط الذي يؤدي عملية القراءة بشكل غير متزامن. أعلم أنه عندما يتم تعيين جميع مهلات قراءة المنفذ التسلسلي إلى الصفر، لن تنتهي عملية القراءة حتى يتم قراءة عدد معين من بايت، ولكن هذا سلوك أدرك ذلك. مسؤولي تتعلق بحالات غير متوقعة التي من شأنها أن تسبب الحدث لا يتم تعيينه أبدا وطريقة الانتظار () للانتظار إلى الأبد - هل من المحتمل أن يحدث؟
2) Waitfor () قد تعرج RETRROR الذي يبلغ أنه حدث بعض الخطأ أثناء عملية الانتظار (ولكن هذا غير مرتبط بعملية القراءة المتداخلة على الإطلاق، أليس كذلك؟). لذلك أعتقد أنني لا ينبغي أن ننتظر عملية القراءة حتى النهاية، لأن مقبض الحدث قد لم يعد قابلا للاستخدام، أليس كذلك؟ لذلك يمكنني استدعاء الأسلوب Cancelio () لإلغاء عملية القراءة، انتظر حتى يتم تعيين الحدث من خلال مؤشر ترابط أداء القراءة الملغاة بشكل غير متزامن بشكل غير متزامن، ثم رفع استثناء. أنتظر حتى يتم إلغاء القراءة من خلال هذا الموضوع لأنه إذا تركت طريقة القراءة الخاصة بي على الفور (دون إلغاء الإدخال / الإخراج)، أود أن أؤدي إلى كتابة موضوع بياناتها (بيانات السجل المتداخلة) إلى المتغيرات المحلية التي من شأنها لم تعد صالحة بعد ذلك، أليس كذلك؟ من ناحية أخرى، هل هناك خطر أن يتم حظر الخيط الحالي إلى الأبد بسبب مكالمة Waitfor (Infinite) قبل زيادة الاستثناء؟
سأكون ممتنا لو تخبرني ما إذا كانت العبارات المذكورة أعلاه صحيحة أو لا تعلق عليها، من فضلك.
شكرا جزيلا لك مقدما.
المحلول
فقط من الفضول: لماذا لا تستخدم مكون تسلسلي موجود؟
أنا أستعمل Tubbopower Async. لاستقبال رسائل GPS، ولكن هناك الكثير من الآخرين متاحين بحرية: http://www.efg2.com/lab/library/delphi/io/portio.htm.
يتيح لك معظم هؤلاء القيام بالتواصل التسلسلي على مستوى أعلى بكثير، ويمجد كل مستوى أقل من IO وخيط الخيوط بالنسبة لك.
بهذه الطريقة عليك فقط كتابة onreceive
معالج لتلقي، والاتصال send()
لإرسال الاشياء.