انتظار مشغول

از ویکی‌پدیا، دانشنامهٔ آزاد
پرش به: ناوبری، جستجو

در مهندسی نرم‌افزار، انتظار مشغول (به انگلیسی: Busy waiting) یا چرخ زدن (به انگلیسی: Spinning) تکنیکی است که در آن یک فرایند، مکرراً یک شرط خاص را بررسی می‌کند تا ببیند آیا آن شرط برقرار است یا خیر. مثلاً پروسه در یک حلقه تکرار مکرراً صفحه‌کلید را بررسی می‌کند تا ببیند آیا ورودی آن در دسترس قرار دارد یا خیر. همچنین از این تکنیک می‌توان برای ایجاد تاخیر زمانی برای یک مدت دلخواه هم استفاده کرد. این تکنیک در سیستم‌هایی استفاده می‌شود که فاقد روشی برای انتظار کشیدن به یک اندازه دلخواه هستند. سرعت پردازنده‌ها از یک رایانه به رایانه‌ای دیگر به شدت متفاوت است، خصوصاً اینکه برخی از پردازنده‌ها طوری طراحی شده‌اند که بر اساس فاکتورهای خارجی مانند بار سیستم‌عامل، سرعت خود را به شکل پویا تنظیم کنند. در نتیجه، در اغلب موارد، استفاده از تکنیک چرخ‌زنی برای ایجاد تاخیر زمانی، باعث بوجود آمدن رویدادهای غیر قابل پیش‌بینی یا بعضاً متناقض می‌شود؛ مگر اینکه کدی پیاده‌سازی شود که تعیین کند پردازنده با چه سرعتی یک حلقه «هیچ کار نکن» را اجرا می‌کند. بنابراین از این تکنیک باید تا جای ممکن دوری کرد. چرا که پردازنده در طی این زمان هیچ کار مفیدی انجام نمی‌دهد.

تکنیک چرخ‌زنی می‌تواند در برخی شرایط یک انتخاب درست باشد، که مهمترین آنها پیاده‌سازی قفل چرخشی در سیستم‌عامل‌هایی است که برای اجرا شدن روی سیستم‌های چند پردازنده‌ای طراحی شده اند. اما به طور کلی، چرخ‌زنی یا انتظار مشغول، یک ضد-الگو است و باید از آن پرهیز نمود. چرا که وقت پردازنده با انجام دادن یک فعالیت بی‌خود به هدر می‌رود، در حالی که در عوض می‌تواند از این وقت برای اجرا کردن یک کار مفید استفاده کند.

مثال به زبان سی[ویرایش]

کد زیر که به زبان برنامه‌نویسی سی نوشته شده است، دو ریسه را نشان می‌دهد که یک متغیر سراسری به نام i را به اشتراک گذاشته‌اند. ریسه اول مکرراً متغیر i را بررسی می‌کند تا ببیند که آیا مقدار آن تغییر کرده است یا نه.

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
 
volatile int i = 0; /* i is global, so it is visible to all functions.
                       It's also marked volatile, because it
                       may change in a way which is not predictable by the compiler,
                       here from a different thread. */
 
/* f1 uses a spinlock to wait for i to change from 0. */
static void *f1(void *p)
{
    while (i==0) {
        /* do nothing - just keep checking over and over */
    } 
    printf("i's value has changed to %d.\n", i);
    return NULL;
}
 
static void *f2(void *p)
{
    sleep(60);   /* sleep for 60 seconds */
    i = 99;
    printf("t2 has changed the value of i to %d.\n", i);
    return NULL;
}
 
int main()
{
    int rc;
    pthread_t t1, t2;
 
    rc = pthread_create(&t1, NULL, f1, NULL);
    if (rc != 0) {
        fprintf(stderr,"pthread f1 failed\n");
        return EXIT_FAILURE;
    }
 
    rc = pthread_create(&t2, NULL, f2, NULL);
    if (rc != 0) {
        fprintf(stderr,"pthread f2 failed\n");
        return EXIT_FAILURE;
    }
 
    pthread_join(t1, NULL);
    pthread_join(t2, NULL);
    puts("All pthreads finished.");
    return 0;
}

در مواردی مانند این، می‌توان از متغیر شرطی در C11 استفاده کرد.

جایگزین انتظار مشغول[ویرایش]

بیشتر سیستم‌عامل‌ها و کتابخانه‌های ریسه‌بندی، تعدادی فراخوان سیستمی دارند که یک فرایند را با رخ دادن رویدادی مسدود می‌کنند. از جمله این رویدادهایی که باعث مسدود شدن یک فرایند می‌شود عبارتند از قفل بودن یک شی و انتظار برای بازشدن آن، تغییرات تایمر، سیگنال‌ها یا در دسترس نبودن ورودی/خروجی. استفاده از چنین فراخوان‌هایی معمولاً راحت‌ترین، موثرترین، عادلانه‌ترین نتایج را در بر دارد که همچنین از بوجود آمدن شرایط رقابتی هم جلوگیری می‌کند.

منابع[ویرایش]

مشارکت‌کنندگان ویکی‌پدیا، «Busy waiting»، ویکی‌پدیای انگلیسی، دانشنامهٔ آزاد (بازیابی در ۲۰ اوت ۲۰۱۳).