هل من الممكن تغيير التعامل مع ذلك تم فتح باب متزامن I/O أن يكون فتح باب إدخال/إخراج غير متزامن أثناء حياته ؟

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

سؤال

معظم حياتي اليومية البرمجة العمل في ويندوز هو في الوقت الحاضر في جميع عمليات الإدخال/الإخراج من كل نوع (الأنابيب, لوحات المفاتيح, ملفات, مآخذ, ...).أنا على علم جيد من أساليب مختلفة من القراءة والكتابة من/إلى أنواع مختلفة من مقابض (متزامن, غير متزامن في انتظار الانتهاء من أحداث ، في انتظار الملف مقابض ، I/O الانتهاء الموانئ ، alertable I/O).نحن نستخدم العديد من تلك.

بعض التطبيقات سيكون من المفيد جدا أن يكون سوى طريقة واحدة لعلاج جميع مقابض.أقصد البرنامج قد لا تعرف ما هو نوع من التعامل معها تلقت ونود أن استخدام, دعنا نقول, I/O الانتهاء الموانئ للجميع.

لذلك أولا أود أن أسأل:

دعونا نفترض أن لدي التعامل مع:

HANDLE h;

التي وردت من قبل بلدي عملية الإدخال/الإخراج من مكان ما.هل هناك أي سهلة وموثوق بها لمعرفة ما أعلام تم إنشاؤه ؟ الرئيسية العلم في المسألة FILE_FLAG_OVERLAPPED.

الطريقة الوحيدة المعروفة حتى الآن ، هو محاولة لتسجيل مثل هذا التعامل في إكمال الإدخال/الإخراج المنفذ (باستخدام CreateIoCompletionPort()).إذا أن ينجح في التعامل معها وقد تم إنشاؤها مع FILE_FLAG_OVERLAPPED.ولكن بعد ذلك فقط I/O إنجاز ميناء يجب أن تستخدم ، المقبض لا يمكن أن يكون غير المسجلة من دون إغلاق HANDLE h نفسها.

وتوفير هناك طريقة سهلة لتحديد وجود FILE_FLAG_OVERLAPPED, هناك سوف يأتي السؤال الثاني:

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

لم أجد أي طريقة مباشرة بعد القراءة من خلال MSDN و غوغلينغ الكثير.سيكون هناك على الأقل بعض الخدع التي يمكن أن تفعل الشيء نفسه ؟ مثل إعادة إنشاء مقبض في نفس الطريقة باستخدام CreateFile() وظيفة أو شيئا من هذا القبيل ؟ شيء حتى جزئيا موثقة أو غير موثقة ؟

المكان الرئيسي حيث كنت بحاجة إلى هذا ، هو تحديد الطريقة (أو تغيير الطريقة) عملية القراءة/الكتابة من مقابض أرسلت إليها من قبل تطبيقات الطرف الثالث.لا يمكننا التحكم في كيفية طرف ثالث المنتجات إنشاء مقابض.

عزيزي ويندوز معلمو:مساعدة من فضلك!

مع التحيات

مارتن

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

المحلول 2

3 سنوات مرت ويندوز 8 لقد تم الافراج.بفضل الانحدار التي أدخلت في تنفيذ وحدة التحكم في ويندوز 8 حصلت على أن تفعل شيئا حيال هذه القضية التي أثار هذا السؤال.لذلك يجب وأخيرا حاولت استخدام ReOpenFile() استدعاء دالة.

في جملة واحدة:لأغراض بلدي فإنه لا طائل منه.

على ReOpenFile() API المستخدمة "أخذ ملف موجود التعامل معها و الحصول على آخر التعامل مع ذلك يحتوي على مجموعة مختلفة من حقوق الوصول".على الأقل هذا هو ما جاء في المقالة الأصلية.

حاولت استخدام ReOpenFile() على وحدة الإدخال التعامل مع:

  stdin_in = GetStdHandle(STD_INPUT_HANDLE);
  stdin_in_operlapped = ReOpenFile(stdin_in, GENERIC_READ | GENERIC_WRITE,
                                   FILE_SHARE_READ, FILE_FLAG_OVERLAPPED);
  if (stdin_in_operlapped ==  INVALID_HANDLE_VALUE)
    {
      my_debug("failed to ReOpen stdin handle with OVERLAPPED flag: %d", GetLastError());
      exit(1);
    }

و ما أحصل عليه هو:خطأ 1168:"لم يتم العثور على عنصر"."شكرا لك مايكروسوفت".لن تحاول حتى أن استخدامه مجهول الأنابيب منذ الوثائق الدول:

"غير متزامن (تتداخل) عمليات القراءة والكتابة غير معتمدة من قبل مجهول الأنابيب.وهذا يعني أنه لا يمكنك استخدام ReadFileEx و WriteFileEx الوظائف مع مجهول الأنابيب.بالإضافة إلى ذلك ، lpOverlapped المعلمة من طلب & readfile و WriteFile هو تجاهلها عند وتستخدم هذه الوظائف مع مجهول الأنابيب."

شكرا لك يا الناس جميعا على اقتراحاتكم.عند القراءة من التعامل معها بشكل غير متزامن ، على المرء أن يكون مستعدا أيضا عن حقيقة أن العملية قد أكمل متزامن.وأنا أعلم.السبب الرئيسي الذي كان طرح هذا السؤال هو:

عندما متزامن قراءة صدرت على بعض الكائنات (على الأقل مجهول الأنابيب إدخال وحدة التحكم في نظام التشغيل Windows 8) ثم يدعو CloseHandle() من موضوع آخر في نفس التعامل معها إما أن تفشل ، أو تعليق ، حتى طلب & readfile() يكمل;وهذا يعني أنه سيكون معلقة إلى أجل غير مسمى في كثير من الحالات.هذا هو السبب في أنني أردت أن تحل محل متزامن التعامل مع غير متزامن.

الآن من الواضح لي أنه هو ببساطة غير ممكن في أنظمة التشغيل ويندوز إلغاء بعض عمليات القراءة في طريقة مباشرة.عند القراءة من متزامن مقابض واحدة فقط للخروج من التطبيق حتى لو طلب & readfile() لا تزال القراءة من التعامل في بعض الصفحات ، لأنه من المستحيل ببساطة موثوق تستيقظ هذه عملية قراءة.في معرفة...في أحدث نظام التشغيل فمن الممكن إلغاء هذه العملية.ومع ذلك ، ليس هناك طريقة لمعرفة الطقس الخيط في طلب & readfile() استدعاء الفعل ، أو ليس بعد.إذا طلب & readfile() لا يسمى بعد ثم لا يوجد أي عملية إلغاء اللاحقة قراءة تعليق.الطريقة الوحيدة التي سوف تكون لإغلاق التعامل معها ، ولكن العملية التي توقف أو فشل في بعض الأشياء على بعض أنظمة التشغيل.فقط حل مناسب لهذا هو غير متزامن I/O.ولكن كما ذكرت في بداية التطبيق لدينا هو بدأ من قبل تطبيقات الطرف الثالث و لا يمكننا إجبار كل منهم دائما إنشاء ممرات تتداخل مع العلم مجموعة stdio.

أنا الاستسلام والذهاب إلى تنفيذ سيئة قبيحة الخارقة...سيكون لدينا للحفاظ على القراءة دون أن تتداخل هيكل من المقابض التي تم إنشاؤها تتداخل مع العلم تسرب مقابض المواضيع....

نصائح أخرى

أرى أنني كنت قارئًا سيئًا لـ MSDN:/ لقد فاتني الوظيفة تمامًا ReOpenFile() الذي تم تقديمه ربما في وقت مبكر من يونيو 2003 في Windows Server 2003 (وفقًا لـ هذه المقالة). للدفاع عن نفسي قليلاً على الأقل: أتوقع CreateFile() وصف للرجوع إلى ReOpenFile() وصف. هناك إشارة على ReOpenFile() صفحة إلى CreateFile() الصفحة ، ولكن ليس العكس جولة.

يبدو أن هذه الوظيفة تمكن بدقة ما أحتاجه: إضافة أو إزالة FILE_FLAG_OVELRAPPED إلى/من المقابض الموجودة بالفعل عن طريق إنشاء مقبض جديد مع الخصائص المطلوبة! : -di لم يختبرها بعد. إنه ، للأسف ، متاح فقط على خادم Windows 2003 و Windows Vista وما فصاعدًا. تم الرد على سؤال حول إصدارات OS السابقة هنا. الوظيفة غير موجودة في API العامة في نظام التشغيل قبل خادم Windows 2003. يتم استخدامه من خلال التنفيذ الأساسي ، لكنه غير متوفر للمطورين على تلك الأنظمة (غير مدعومة).

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

علاوة على ذلك ، ما زلت أفتقد جزءًا من الإجابة: هل يمكن اختبار وجود الأعلام بأي وسيلة؟ لم أجد وظيفة للقيام بذلك. هذا يعني أنه إذا أردنا ضمان وجود بعض العلامات في كائن الملف ، فيجب إعادة فتح الملف دائمًا.

إذا فهمت ما الذي تتبعه ، أود أن أقترح أنك لا تهتم إذا تم فتحها بعلم متداخل أم لا. أعتقد أنه يمكنك المرور بأمان في OVERLAPPED بنية في كل من الحالات المتزامنة وغير المتزامنة. يجب أن يكون الكود الخاص بك قادرًا على التعامل معه ReadFile() عودة false و GetLastError() عودة ERROR_IO_PENDING. ستحتاج أيضًا إلى إضافة المكالمات المناسبة إلى GetOverlappedResult(), WaitForSingleObject(), ، إلخ.

مقالة MSDN على ReadFile() لديه بعض المعلومات الجيدة حول هذا الأمر تحت "اعتبارات العمل مع مقابض الملف المتزامنة" ، و "اعتبارات للعمل مع مقابض الملفات غير المتزامنة" في قسم "التزامن وموضع الملف".

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

أعتقد أن الشيء المحدد حقًا هو الطريقة التي تقول بها وثائق ReadFile "إذا تم فتح Hfile مع file_flag_overlapped ، يمكن للوظيفة الإبلاغ بشكل غير صحيح أن عملية القراءة قد اكتملت."

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

لا أعرف طريقة لتحديد علم المقبض والآثار الجانبية لاستخدام API إعادة فتح ، ولكن منذ أن كان هدفك

سيكون من المفيد جدًا أن يكون لديك طريقة واحدة فقط لعلاج جميع المقابض

إذا كنت ترغب في سلوك متزامن (أعني استخدام واجهة برمجة التطبيقات المتزامنة لمقابض غير متداخلة و API غير المتزامن مع بنية متداخلة مع انتظار لاحق على حدث التداخل) يمكنك دائمًا استخدام واجهة برمجة تطبيقات ASYNC أيضًا إذا تم فتح المقبض في وضع غير متداخل كما ذكرت بالفعل من قبل Brett
أستطيع أن أؤكد أن هذا يعمل (على الأقل للأنابيب المسماة) es:

void connectSynchronous(HANDLE hPipeThatWeDontKnowItsFlag){
    ...
    BOOL bRet = ::ConnectNamedPipe(hPipeThatWeDontKnowItsFlag, pOverlapped);

    if(bRet == FALSE){
        DWORD dwLastErr = ::GetLastError();

        if(dwLastErr == ERROR_IO_PENDING){
            //The handle was opened for asynchronous IO so we have to wait for the operation
            ...waitFor on the overlapped hEvent;

        }else if(dwLastErr == ERROR_PIPE_CONNECTED){
            //The handle was opened for synchronous IO and the client was already connected before this call: that's OK!
            return;
        }else{
            throw Error(dwLastErr);
        }
    }/*else{
        //The handle was opened for synchronous IO and the client has connected: all OK
    }*/
}

يتمثل بديل لـ CreateIoCompletionport Hack في القيام بقراءة بايت صفر مع lpoverled null. إذا فشل مع error_invalid_parameter ، افترض أنه تم فتحه مع file_flag_overlapped.

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