انتظار مشغول
در مهندسی نرمافزار، انتظار مشغول (به انگلیسی: 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». در دانشنامهٔ ویکیپدیای انگلیسی، بازبینیشده در ۲۰ اوت ۲۰۱۳.