سؤال

أحصل على خطأ غريب. لقد قمت بتنفيذ هاتين الوظيفتين:

int flag_and_sleep(volatile unsigned int *flag)
{
    int res = 0;

    (*flag) = 1;

    res = syscall(__NR_futex, flag, FUTEX_WAIT, 1, NULL, NULL, 0);
    if(0 == res && (0 != (*flag)))
        die("0 == res && (0 != (*flag))");
    return 0;
}

int wake_up_if_any(volatile unsigned int *flag)
{
    if(1 == (*flag))
    {
        (*flag) = 0;
        return syscall(__NR_futex, flag, FUTEX_WAKE, 1, NULL, NULL, 0);
    }
    return 0;
}

واختبارها عن طريق تشغيل موضوعين posix:

static void die(const char *msg)
{
    fprintf(stderr, "%s %u %lu %lu\n", msg, thread1_waits, thread1_count, thread2_count);
    _exit( 1 );
}

volatile unsigned int thread1_waits = 0;

void* threadf1(void *p)
{
    int res = 0;
    while( 1 )
    {
        res = flag_and_sleep( &thread1_waits );
        thread1_count++;
    }
    return NULL;
}

void* threadf2(void *p)
{
    int res = 0;
    while( 1 )
    {
        res = wake_up_if_any( &thread1_waits );
        thread2_count++;
    }

    return NULL;
}

بعد أن كان لدى Thread2 مليون أو نحو ذلك ، أحصل على النار على لي:

./a.out 0 == res && (0! = (*flag)) 1 261129 1094433

هذا يعني أن syscall - وبالتالي do_futex () - عاد 0. رجل يقول إنه يجب أن يفعل ذلك فقط إذا استيقظت من خلال مكالمة do_futex (wake). ولكن قبل أن أقوم بإجراء مكالمة استيقاظ ، قمت بتعيين العلم على 0. يبدو هنا أن العلم لا يزال 1.

هذا هو Intel ، مما يعني نموذج ذاكرة قوي. لذلك إذا كنت في Thread1 ، أرى نتائج من syscall في Thread2 ، يجب أن أرى أيضًا نتائج الكتابة في الموضوع 2 الذي كان قبل المكالمة.

العلم وجميع المؤشرات إليها متقلبة ، لذلك لا أرى كيف يمكن أن تفشل GCC في قراءة القيمة الصحيحة.

أنا محير.

شكرًا!

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

المحلول

يحدث السباق عندما يذهب الخيط 1 إلى الدورة الكاملة وإعادة الدخول إلى المكالمة عندما ينتقل الموضوع 2

(*flag) = 0;

ل

return syscall(__NR_futex, flag, FUTEX_WAKE, 1, NULL, NULL, 0);

لذلك الاختبار معيب.

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