سؤال

إذا أردت أن أكتب:

int selectedChannels = selector.select();
Set selectedKeys = selector.selectedKeys();
if ( selectedChannels != selectedKeys.size() ) {
    // Selector.select() returned because of a call to Selector.wakeup()
    // so do synchronization.
}
// Continue with handling selected channels.

هل صحيح الكشف عن التنبيه-الدعوة ؟

Backgroundinformation:

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

SocketChannel channel = SocketChannel.open();
channel.configureBlocking( false );
channel.connect( new InetSocketAddress( InetAddress.getLocalHost(), PORT ));
selector.wakeup();
SelectionKey key = channel.register( selector, SelectionKey.OP_CONNECT );

المشكلة هي أن SelectableChannel.سجل() قد منع إذا كان الموضوع الرئيسي هو بالفعل في محدد.حدد().لمنع هذا من الحدوث ادعو محدد.التنبيه() الذي دعونا الخيط الرئيسي العودة قبل الأوان من حدد().للتأكد من موضوع آخر فرصة لاستكمال تسجيل مكالمة ، وأود أن مزامنة الموضوع الرئيسي ، ولكن أود أن تفعل ذلك بعد كل العودة من حدد().إذا أنا يمكن الكشف عن ما إذا كان عاد من حدد() بسبب التنبيه() مكالمة ، ثم يمكن تحسين ذلك فقط في هذه الحالة.

لذا نظريا أعلى مقتطف الشفرة يجب أن تعمل, ولكن كنت أتساءل إذا كان من سوى ذلك لأنه يعتمد على بعض غير محدد السلوك ؟

شكرا على أي تلميحات.

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

المحلول

وأود أن أعتقد أن المقترح مقتطف لا تعمل على الإطلاق من حيث المبدأ ، في عقود Selector#select() و Selector#selectedKeys().من محدد:

  • المختارة-مجموعة رئيسية هي مجموعة من المفاتيح مثل أن كل مفتاح القناة تم الكشف عن أن تكون جاهزة واحد على الأقل من العمليات المحددة في المفتاح الفائدة خلال قبل عملية الاختيار.هذه المجموعة تم إرجاعها بواسطة selectedKeys الأسلوب.
public abstract int select(long timeout)
                throws IOException
    Returns:
        The number of keys, possibly zero, whose ready-operation sets were
        updated

كما قرأت أن حجم selectedKeys تعيين ينبغي دائما يساوي عدد إرجاعها من قبل select من خلال التعريف.وقد لاحظت - كما قد يكون كذلك - أن بعض التطبيقات لا تتبع تماما الوثائق ، في الواقع selectedKeys إرجاع كافة مفاتيح مع تحديث جاهزة العملية مجموعات ، حتى لو لم يتم تحديثها خلال مكالمة select.سوى مؤشر آخر على أن تحديد استيقظت بسبب مكالمة wakeup قد يكون عدد المفاتيح هو الصفر ، ومع ذلك إما أن يكون طريقة يمكن الاعتماد عليها في أفضل الأحوال.

الطريقة المعتادة للتعامل مع هذا ضمنا ، من خلال التزامن التحكم.لا تقلق وقت التنفيذ هنا ؛ هذا مثال كلاسيكي من السابق لأوانه الأمثل.

إلا إذا كنت قلقا حقا حول رقم واحد ميكروثانية التحمل ، فإنك لن تلاحظ أي تباطؤ - و إذا كنت قلقا حول هذا المستوى من التسامح ، Selector لن تكون موثوقة بما فيه الكفاية بالنسبة لك على أي حال.

هنا مثال من المعتاد آلية هذا باستخدام ReentrantLock لإنجاز المناسبة التزامن:

ReentrantLock selectorGuard;
Selector selector;

private void doSelect() {
    // Don't enter a select if another thread is in a critical block
    selectorGuard.lock();
    selectorGuard.unlock();

    selector.select();
    Iterator<SelectionKey> keyIter = selector.selectedKeys().iterator();

    while(keyIter.hasNext()) {

        SelectionKey key = keyIter.next();
        keyIter.remove();

        // Process key
    }
}

private void addToSelector() {

    // Lock the selector guard to prevent another select until complete
    selectorGuard.lock();

    try {
        selector.wakeup();

        // Do logic that registers channel with selector appropriately

    } finally {
        selectorGuard.unlock();
    }
}

نصائح أخرى

أنا لا أفهم لماذا التعليمات البرمجية الخاصة بك سوف تعمل في العامة.

لماذا لا تحقق volatile بعد select?

إذا select() بإرجاع صفر ، إما أنها انتهت أو كان استيقظ.

حقا لا يمكنك أن تكون على يقين من أن السبب الوحيد محدد استيقظت كان بسبب جرس إنذار.قد يكون لديك أيضا مأخذ النشاط.

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

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