سؤال

أنا أكتب تطبيقًا يمنع الإدخال من اثنين istreams.

القراءة من أي منهما istream هي مكالمة متزامنة (حظر)، لذلك قررت إنشاء اثنين Boost::threadللقيام بالقراءة.

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

وبالتالي، لا أستطيع join() على كلا الخيطين، لأن خيطًا واحدًا فقط (لا يمكن تحديده مسبقًا) سيعود فعليًا (إلغاء الحظر).

يجب أن أجبر الآخر على الخروج بطريقة ما، لكنه محظور في انتظار الإدخال، لذلك لا يمكنه بنفسه أن يقرر أن الوقت قد حان للعودة (متغيرات الحالة أم لا).

هل طريقهم إما:

  • أرسل إشارة دفعة::خيط، أو
  • فرض ان istream إلى "الفشل"، أو
  • قتل دفعة :: موضوع؟

ملحوظة:

  • واحد من istreams يكون cin
  • أحاول إعادة تشغيل العملية، لذلك لا أستطيع إغلاق تدفقات الإدخال بطريقة تمنع إعادة تعيينها.

يحرر:

  • أعرف متى يتم الوصول إلى "النهاية"، وأعرف أي خيط تم الانتهاء منه بنجاح، وأي خيط يجب إيقافه.إنه القتل الذي أحتاج إلى اكتشافه (أو استراتيجية مختلفة للقراءة من istream).
  • أحتاج إلى خروج كلا الموضوعين وتنظيفهما بشكل صحيح :(

شكرًا!

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

المحلول

لا أعتقد أن هناك طريقة للقيام بذلك عبر الأنظمة الأساسية، ولكن يجب أن يكون pthread_cancel هو ما تبحث عنه.مع موضوع دفعة يمكنك الحصول على original_handle من موضوع، واستدعاء pthread_cancel عليه.

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

نصائح أخرى

نعم هنالك!

boost::thread::terminate() سوف تفعل هذه المهمة لمواصفاتك.

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

الإنهاء ليس فوريًا.(الخيط الخطأ يعمل في تلك اللحظة، على أي حال.)

يحدث ذلك في ظل ظروف محددة مسبقًا - ربما يكون الخيار الأكثر ملاءمة لك عند الاتصال boost::this_thread::sleep();, ، والذي يمكنك جعل هذا الخيط يفعله بشكل دوري.

إذا تم حظر مؤشر ترابط معزز لعملية الإدخال / الإخراج (على سبيل المثال. cin>>whatever), boost::thread::terminate() لن يقتل الخيط. cin الإدخال/الإخراج ليس نقطة إنهاء صالحة.صيد 22.

حسنًا على نظام التشغيل Linux، أستخدم pthread_signal(SIGUSR1)، لأنه يقاطع حظر الإدخال والإخراج.لا يوجد مثل هذا الاتصال على النوافذ كما اكتشفته عند نقل الكود الخاص بي.فقط مكالمة مهملة في مأخذ التوصيل للقراءة.في نظام التشغيل Windows، يتعين عليك تحديد حدث من شأنه مقاطعة مكالمة الحظر الخاصة بك بشكل صريح.لذلك لا يوجد شيء مثل (AFAIK) كطريقة عامة لمقاطعة حظر الإدخال/الإخراج.

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

while(!stopped && !interrupted)
{
    io.blockingCall(timeout);
    if(!stopped && !interrupted)
    {
        doSomething();
    }
}

ثم تقوم بمقاطعة خيطيك وضمهما ...

ربما هو أبسط في حالتك؟إذا كان لديك مؤشر ترابط رئيسي يعرف أن أحد المواضيع قد انتهى، فما عليك سوى إغلاق إدخال الإدخال (IO) للخيط الآخر؟

يحرر:بالمناسبة أنا مهتم بالحل النهائي الذي لديك ...

لقد واجهت مشكلة مماثلة بنفسي وتوصلت إلى هذا الحل الذي قد يجده بعض القراء الآخرين لهذا السؤال مفيدًا:

على افتراض أنك تستخدم متغير شرط مع أمر wait()، فمن المهم بالنسبة لك أن تعرف أنه في Boost، عبارة wait() هي نقطة مقاطعة طبيعية.لذا، ما عليك سوى وضع كتلة محاولة/التقاط حول الكود مع عبارة الانتظار والسماح للوظيفة بالانتهاء بشكل طبيعي في كتلة الالتقاط الخاصة بك.

الآن، بافتراض أن لديك حاوية بها مؤشرات خيطك، قم بالتكرار فوق مؤشرات خيطك واستدعاء المقاطعة () على كل خيط، متبوعة بـ join ().

الآن ستنتهي جميع سلاسل الرسائل الخاصة بك بأمان ويجب أن تعمل أي عملية تنظيف للذاكرة متعلقة بـ Boost بشكل نظيف.

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

في التعزيز: الموضوع الذي تبحث عنه timed_join وظيفة.

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

أنت تتحدث عن القراءة من istream، لكن istream هو مجرد واجهة.بالنسبة لـ stdin، يمكنك فقط إغلاق واصف ملف stdin لمقاطعة القراءة.أما الآخر فيعتمد على المكان الذي تقرأ منه..

يبدو أن المواضيع لا تساعدك على فعل ما تريد بطريقة بسيطة.إذا لم يعجبك Boost.Asio، ففكر في استخدامه select().

الفكرة هي الحصول على واصفين للملفات واستخدامهما select() لإخبارك أي منهم لديه مدخلات متاحة.واصف الملف ل cin عادة STDIN_FILENO;تعتمد كيفية الحصول على الآخر على تفاصيلك (إذا كان ملفًا، فقط open() ذلك بدلاً من استخدامه ifstream).

يتصل select() في حلقة لمعرفة المدخلات التي يجب قراءتها، وعندما تريد التوقف، ما عليك سوى الخروج من الحلقة.

ضمن نظام التشغيل Windows، استخدم QueueUserAPC لوضع قائمة الانتظار على proc الذي يطرح استثناءً.هذا النهج يعمل بشكل جيد بالنسبة لي.

لكن:لقد وجدت للتو أن كائنات المزامنة المعززة وما إلى ذلك ليست "قابلة للتنبيه" على نظام Win32، لذا لا يمكن لـ QueueUserAPC مقاطعتها.

متأخر جدًا، ولكن في نظام التشغيل Windows (وهي سلائف مثل VMS أو RSX لأولئك الذين يتذكرون مثل هذه الأشياء) سأستخدم شيئًا مثل ReadFileEx مع روتين إكمال يرسل إشارة عند الانتهاء، وCancelIO إذا كانت هناك حاجة إلى إلغاء القراءة مبكرًا.

يحتوي Linux/BSD على واجهة برمجة تطبيقات أساسية مختلفة تمامًا وليست مرنة.إن استخدام pthread_kill لإرسال إشارة يعمل بالنسبة لي، مما سيؤدي إلى إيقاف عملية القراءة/الفتح.

من المفيد تنفيذ تعليمات برمجية مختلفة في هذا المجال لكل منصة، IMHO.

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