وفقًا لوظيفة MSDN readfile () ، قد تقوم دالة Win32 بالإبلاغ عن إكمال عملية القراءة بشكل غير صحيح. متي؟

StackOverflow https://stackoverflow.com/questions/2472810

سؤال

تنص MSDN في وصفها ReadFile() وظيفة:

إذا تم فتح hfile مع FILE_FLAG_OVERLAPPED, ، يجب أن تشير المعلمة lpoverled OVERLAPPED بنية ، وإلا يمكن للوظيفة الإبلاغ بشكل غير صحيح أن عملية القراءة كاملة.

لدي بعض التطبيقات التي تنتهك التوصية أعلاه وأود أن أعرف شدة المشكلة. أعني أن البرنامج يستخدم الأنابيب المسماة التي تم إنشاؤها مع FILE_FLAG_OVERLAPPED, ، لكنه يقرأ منه باستخدام المكالمة التالية:

ReadFile(handle, &buf, n, &n_read, NULL);

هذا يعني أنه يمر NULL كما lpOverlapped معامل. يجب ألا تعمل هذه المكالمة بشكل صحيح في بعض الحالات وفقًا للوثائق. لقد قضيت الكثير من الوقت في محاولة لإعادة إنتاج المشكلة ، لكنني لم أتمكن من ذلك! لقد حصلت دائمًا على جميع البيانات في المكان المناسب في الوقت المناسب. كنت أختبر أنابيب تدعى فقط.

هل سيعرف أي شخص متى يمكنني أن أتوقع أن يعود ReadFile () بشكل غير صحيح والإبلاغ عن الانتهاء بنجاح حتى حتى البيانات لم يتم بعد ذلك في المخزن المؤقت؟ ماذا يجب أن يحدث من أجل إعادة إنتاج المشكلة؟ هل يحدث ذلك مع الملفات أو الأنابيب أو المقابس أو لوحات المفاتيح أو الأجهزة الأخرى؟ هل يجب علي استخدام نسخة معينة من نظام التشغيل؟ أو إصدار معين من القراءة (مثل تسجيل المقبض على منفذ إكمال I/O)؟ أو التزامن خاص لعمليات القراءة والكتابة/المواضيع؟

أو متى سيفشل ذلك؟ إنه يعمل بالنسبة لي:/

الرجاء المساعدة!

فيما يتعلق ، مارتن

هل كانت مفيدة؟

المحلول

داخليًا ، يدعم النظام فقط I/O غير متزامن. للإدخال/الإخراج المتزامن ، يخلق النظام مؤقتًا OVERLAPPED هيكل مع hEvent = NULL;, ، يصدر طلب I/O غير متزامن تمرير هذا مؤقتًا ، ثم ينتظر الانتهاء باستخدام getOverloppedResult (bwait = true).

تذكر أن hEvent المؤقتة OVERLAPPED الهيكل NULL وانتبه إلى قسم الملاحظات getOverloppedResult:

إذا كان عضو Hevent في الهيكل المتداخل فارغًا ، يستخدم النظام حالة مقبض HFILE للإشارة عند اكتمال العملية.

ملف HANDLE هو كائن قابل للانتظار يصبح غير مواقد عندما تبدأ عملية الإدخال/الإخراج ، ويشير إلى عندما تنتهي عملية الإدخال/الإخراج.

الآن فكر في سيناريو حيث ملف غير متزامن HANDLE لديه طلب I/O المعلق في الوقت الذي تصدر فيه طلب I/O متزامن. النظام يخلق OVERLAPPED الهيكل وينتظر على hfile HANDLE لانتهاء. في غضون ذلك ، يكمل I/O غير المتزامن ، مما يشير إلى HANDLE مما تسبب في عودة I/O المتزامنة قبل الأوان دون الانتهاء بالفعل.

والأسوأ من ذلك أنه بحلول الوقت الذي يتم فيه إكمال I/O غير المتزامن الذي بدأ استجابة لطلب الإدخال/الإخراج المتزامن ، سيقوم بتحديث المؤقت OVERLAPPED بنية لم تعد موجودة. والنتيجة هي فساد الذاكرة.

يمكن العثور على القصة الكاملة في الشيء الجديد القديم.

نصائح أخرى

يبدو أنك في موقف تقوم فيه بالاتصال عن عمد واجهة برمجة تطبيقات في مخالفة لأفضل الممارسات الموثقة. في مثل هذه الحالات ، كل الرهانات متوقفة. فإنه قد عمل، فإنه لا يجوز. إذا كانت قد تعمل على نظام التشغيل هذا ، ولكن ليس على التكرار التالي لنظام التشغيل ، أو حزمة الخدمة التالية لنفس نظام التشغيل. ماذا يحدث عندما تقوم بالمنفذ إلى Win64؟ هل ستظل تعمل بعد ذلك؟

هل يعطي استدعاء getLasterror () (أو النظر إلى @err ، HR في مصحح الأخطاء) أي قيمة مفيدة بالإضافة إلى رمز الخطأ؟

أوصي بأن تسميها بهيكل متداخلة صالح ، وتجعله يعمل وإزالة كل الشك (وإمكانية فشل عشوائي). لماذا ربما يكون لديك رمز عربات التي تجرها الدواب (ومن الصعب للغاية إعادة إنتاج الأخطاء) في برنامجك عندما يمكنك إصلاح المشكلة بسهولة باستخدام بنية متداخلة صالحة؟

لماذا تسأل السؤال بدلاً من إصلاح الكود للاتصال بآبار واجهة برمجة التطبيقات كما كان المقصود؟

أظن أنه يبدو أنه يعمل دائمًا لأنه ، على الرغم من أن هذا I/O غير متزامن ، فإنه يكمل بسرعة كبيرة. اعتمادًا على كيفية اختبارك للنجاح ، من الممكن أن تكون الوظيفة تقارير بشكل غير صحيح عن أن العملية قد اكتملت ، لكنها تكمل بالفعل قبل اختبار النتائج.

سيكون الاختبار الحقيقي هو إجراء قراءة على الأنبوب قبل وجود بيانات يمكن قراءتها.

ولكن في الحقيقة ، يجب عليك فقط إصلاح الرمز. إذا لم تتمكن الهندسة المعمارية من التعامل مع I/O غير متزامن ، فقم بإزالة FILE_FLAG_OVERLAPPED من إنشاء الأنابيب المسماة.

عندما يقولون

blockquote إذا تم فتح hfile مع file_flag_overlisped ، يجب أن تشير المعلمة lpoverled إلى بنية متداخلة صالحة وفريدة من نوعها ، وإلا فإن الوظيفة يمكن أن الإبلاغ بشكل غير صحيح بأن عملية القراءة قد اكتملت.

إنها تعني أنه لا يوجد شيء في الكود الذي يمنعه من العمل ، ولكن هناك أيضًا مسار من خلال الكود الذي يمكن أن ينتج عنه نتائج خاطئة. لمجرد أنه لا يمكنك إعادة إنتاج المشكلة في أجهزتك الخاصة لا يعني أنه لا توجد مشكلة.

إذا كنت ترغب حقًا في إعادة إنتاج هذه المشكلة ، فاترك الرمز كما هي واستمر في حياتك. في الوقت الذي نسيت فيه كل شيء عن هذه المشكلة ، سوف يظهر السلوك الغريب الذي لن يكون له أي علاقات واضحة للاتصال بقراءة. ستقضي أيامًا في سحب شعرك ، وستظهر المشكلة وتذهب بشكل عشوائي. في النهاية ستجدها وركل نفسك لعدم اتباع التعليمات. كنت هناك ، فعلت ذلك ، لا متعة!

الطريقة الأخرى لإعادة إنشاء المشكلة هي جدولة عرض تجريبي مهم لعميلك. من المؤكد أن تفشل بعد ذلك!

إذا كنت لا ترغب في رش الكود الخاص بك بهياكل متداخلة وجميع عمليات فحص قيمة الإرجاع ذات الصلة ، والانتظار ، والأحداث ، وما إلى ذلك ، يمكنك كتابة وظيفة التفاف تأخذ مقبضًا يمكن للقراءة منها ، ومهلة. ما عليك سوى استبدال مكالماتك لإعادة القراءة باستخدام هذا الغلاف المفيد.

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